@tom2012/cc-web 2026.5.20-b → 2026.5.24-a
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/README.md +1 -1
- package/backend/dist/__tests__/browser-proxy.test.d.ts +2 -0
- package/backend/dist/__tests__/browser-proxy.test.d.ts.map +1 -0
- package/backend/dist/__tests__/browser-proxy.test.js +306 -0
- package/backend/dist/__tests__/browser-proxy.test.js.map +1 -0
- package/backend/dist/index.d.ts.map +1 -1
- package/backend/dist/index.js +5 -0
- package/backend/dist/index.js.map +1 -1
- package/backend/dist/notify-service.d.ts +1 -0
- package/backend/dist/notify-service.d.ts.map +1 -1
- package/backend/dist/notify-service.js +1 -0
- package/backend/dist/notify-service.js.map +1 -1
- package/backend/dist/routes/browser-proxy.d.ts +31 -0
- package/backend/dist/routes/browser-proxy.d.ts.map +1 -0
- package/backend/dist/routes/browser-proxy.js +363 -0
- package/backend/dist/routes/browser-proxy.js.map +1 -0
- package/frontend/dist/assets/{ChatOverlay-C6C_KmoQ.js → ChatOverlay-W-pSFHsV.js} +1 -1
- package/frontend/dist/assets/{GraphPreview-3Jt6HVoR.js → GraphPreview-CcuxUzQH.js} +1 -1
- package/frontend/dist/assets/{MobilePage-Ccfw-PQN.js → MobilePage-DEBO3i1o.js} +3 -3
- package/frontend/dist/assets/{OfficePreview-CcNfdvDk.js → OfficePreview-DY-ew_ex.js} +2 -2
- package/frontend/dist/assets/{PdfPreview-C_TVMGcZ.js → PdfPreview-Bl0MS_5m.js} +1 -1
- package/frontend/dist/assets/{ProjectPage-DdDicE9q.js → ProjectPage-tcwSSEFX.js} +5 -5
- package/frontend/dist/assets/SettingsPage-DU649aEa.js +13 -0
- package/frontend/dist/assets/{SkillHubPage-qYjj_wYZ.js → SkillHubPage-hH5XcB57.js} +2 -2
- package/frontend/dist/assets/{chevron-down-UeSwXtvj.js → chevron-down-B3q2CU-d.js} +1 -1
- package/frontend/dist/assets/{index-e0TiJwv-.js → index-CZOz50el.js} +1 -1
- package/frontend/dist/assets/{index-BoEETvjx.js → index-DsYny3RQ.js} +1 -1
- package/frontend/dist/assets/{index-Bf5BlYFK.js → index-nYsy3LMF.js} +3 -3
- package/frontend/dist/assets/{jszip.min-PNrxBYIs.js → jszip.min-9o6zKk8v.js} +1 -1
- package/frontend/dist/assets/{search-DY3wMq7s.js → search-B9B3Cq4V.js} +1 -1
- package/frontend/dist/assets/select-BOLkADQv.js +13 -0
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
- package/frontend/dist/assets/SettingsPage-GCr7_tnl.js +0 -13
- package/frontend/dist/assets/select-CYI-GI6f.js +0 -13
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.parseHostport = parseHostport;
|
|
37
|
+
exports.isAllowedProxyIp = isAllowedProxyIp;
|
|
38
|
+
exports.resolveAllowedTarget = resolveAllowedTarget;
|
|
39
|
+
exports.rewriteHtml = rewriteHtml;
|
|
40
|
+
exports.rewriteLocationHeader = rewriteLocationHeader;
|
|
41
|
+
const express_1 = require("express");
|
|
42
|
+
const dns = __importStar(require("dns/promises"));
|
|
43
|
+
const net = __importStar(require("net"));
|
|
44
|
+
const jwt = __importStar(require("jsonwebtoken"));
|
|
45
|
+
const auth_1 = require("../auth");
|
|
46
|
+
const config_1 = require("../config");
|
|
47
|
+
const logger_1 = require("../logger");
|
|
48
|
+
const log = (0, logger_1.modLogger)('browser-proxy');
|
|
49
|
+
const router = (0, express_1.Router)();
|
|
50
|
+
const BLOCKED_PORTS = new Set([
|
|
51
|
+
22, 23, 25, 110, 143, 465, 587, 993, 995,
|
|
52
|
+
2049, 3389, 5432, 5984, 6379, 9200, 11211, 27017,
|
|
53
|
+
]);
|
|
54
|
+
const STRIPPED_RESPONSE_HEADERS = new Set([
|
|
55
|
+
'x-frame-options',
|
|
56
|
+
'frame-options',
|
|
57
|
+
'content-security-policy',
|
|
58
|
+
'content-security-policy-report-only',
|
|
59
|
+
'cross-origin-opener-policy',
|
|
60
|
+
'cross-origin-embedder-policy',
|
|
61
|
+
'cross-origin-resource-policy',
|
|
62
|
+
'set-cookie',
|
|
63
|
+
'content-length',
|
|
64
|
+
'transfer-encoding',
|
|
65
|
+
'content-encoding',
|
|
66
|
+
// P1 (codex review): upstream must not be able to clobber ccweb's
|
|
67
|
+
// own cookies/storage or register service workers on the daemon origin.
|
|
68
|
+
'clear-site-data',
|
|
69
|
+
'service-worker-allowed',
|
|
70
|
+
'permissions-policy',
|
|
71
|
+
'feature-policy',
|
|
72
|
+
]);
|
|
73
|
+
// CSP sandbox without allow-same-origin forces an opaque origin even for
|
|
74
|
+
// same-origin iframes — proxied page JS cannot reach ccweb's localStorage
|
|
75
|
+
// / IndexedDB / cookies. Pair with the `<iframe sandbox>` attribute on the
|
|
76
|
+
// frontend so a direct GET to /api/browser-proxy/... in another tab is
|
|
77
|
+
// also opaque.
|
|
78
|
+
const PROXY_HTML_CSP = "sandbox allow-scripts allow-forms allow-popups";
|
|
79
|
+
const MAX_PROXY_SIZE = 16 * 1024 * 1024;
|
|
80
|
+
const UPSTREAM_TIMEOUT_MS = 15000;
|
|
81
|
+
// Cloud metadata services + IPv4 link-local that should NEVER be reachable.
|
|
82
|
+
// 169.254.169.254 = AWS/GCP/Azure metadata. 169.254.170.2 = ECS task role.
|
|
83
|
+
const BLOCKED_IPS = new Set(['169.254.169.254', '169.254.170.2']);
|
|
84
|
+
const BLOCKED_HOSTS = new Set(['metadata.google.internal', 'metadata']);
|
|
85
|
+
// Cookie issued by /_session and required by the proxy. Path-scoped so it
|
|
86
|
+
// never leaks to other ccweb routes; HttpOnly so the proxied iframe's JS
|
|
87
|
+
// can't read it; SameSite=Lax because the iframe is loaded same-origin.
|
|
88
|
+
const COOKIE_NAME = 'ccweb_bp';
|
|
89
|
+
const COOKIE_MAX_AGE_SEC = 60 * 60;
|
|
90
|
+
function parseHostport(raw) {
|
|
91
|
+
// v0: http only. IPv6 literals out of scope (path-segment ambiguity).
|
|
92
|
+
const m = raw.match(/^([a-zA-Z0-9.\-_]+):(\d{1,5})$/);
|
|
93
|
+
if (!m)
|
|
94
|
+
return null;
|
|
95
|
+
const host = m[1].toLowerCase();
|
|
96
|
+
const port = Number(m[2]);
|
|
97
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
98
|
+
return null;
|
|
99
|
+
if (BLOCKED_PORTS.has(port))
|
|
100
|
+
return null;
|
|
101
|
+
return { host, port };
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Allowlist check on a literal IPv4/IPv6 address. Unlike notify-service's
|
|
105
|
+
* isPrivateAddress (which is a deny-list for outbound webhooks and uses
|
|
106
|
+
* loose startsWith on the *hostname*), this is strictly numeric and refuses
|
|
107
|
+
* the cloud-metadata link-local addresses even though they're RFC1918.
|
|
108
|
+
*/
|
|
109
|
+
function isAllowedProxyIp(addr) {
|
|
110
|
+
const a = addr.replace(/^\[|\]$/g, '').toLowerCase();
|
|
111
|
+
const mapped = a.match(/^::ffff:(\d{1,3}(?:\.\d{1,3}){3})$/);
|
|
112
|
+
if (mapped)
|
|
113
|
+
return isAllowedProxyIp(mapped[1]);
|
|
114
|
+
// Reject anything that isn't a real IP — without this `10.evil.com`
|
|
115
|
+
// would match the `/^10\./` prefix below and slip through.
|
|
116
|
+
if (!net.isIP(a))
|
|
117
|
+
return false;
|
|
118
|
+
if (BLOCKED_IPS.has(a))
|
|
119
|
+
return false;
|
|
120
|
+
if (a === '0.0.0.0' || a === '::1')
|
|
121
|
+
return true;
|
|
122
|
+
if (/^127\./.test(a))
|
|
123
|
+
return true;
|
|
124
|
+
if (/^10\./.test(a))
|
|
125
|
+
return true;
|
|
126
|
+
if (/^192\.168\./.test(a))
|
|
127
|
+
return true;
|
|
128
|
+
if (/^172\.(1[6-9]|2\d|3[01])\./.test(a))
|
|
129
|
+
return true;
|
|
130
|
+
if (/^fc/.test(a) || /^fd/.test(a))
|
|
131
|
+
return true; // ULA v6
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Resolve hostname to a single IP (or accept literal IP) and confirm it's
|
|
136
|
+
* in the allowed private range. Returns the resolved IP to pin against
|
|
137
|
+
* DNS-rebinding TOCTOU: callers fetch by IP, not by hostname.
|
|
138
|
+
*/
|
|
139
|
+
async function resolveAllowedTarget(host) {
|
|
140
|
+
const h = host.replace(/\.$/, '').toLowerCase();
|
|
141
|
+
if (BLOCKED_HOSTS.has(h))
|
|
142
|
+
return null;
|
|
143
|
+
if (h === 'localhost')
|
|
144
|
+
return '127.0.0.1';
|
|
145
|
+
if (net.isIP(h))
|
|
146
|
+
return isAllowedProxyIp(h) ? h : null;
|
|
147
|
+
try {
|
|
148
|
+
const records = await dns.lookup(h, { all: true, verbatim: true });
|
|
149
|
+
if (records.length === 0)
|
|
150
|
+
return null;
|
|
151
|
+
if (!records.every((r) => isAllowedProxyIp(r.address)))
|
|
152
|
+
return null;
|
|
153
|
+
return records[0].address;
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Rewrite root-relative absolute paths (src/href/action="/...") through
|
|
161
|
+
* this proxy. Also strip any upstream `<base href="...">` so the original
|
|
162
|
+
* declaration cannot redirect relative resolution back out to the bare
|
|
163
|
+
* ccweb origin. Protocol-relative and relative paths are untouched —
|
|
164
|
+
* browser resolves them against the iframe URL which is already proxied.
|
|
165
|
+
*/
|
|
166
|
+
function rewriteHtml(html, prefix) {
|
|
167
|
+
return html
|
|
168
|
+
.replace(/<base\b[^>]*>/gi, '')
|
|
169
|
+
.replace(/\b(src|href|action)\s*=\s*(["'])\/(?!\/)([^"']*)\2/gi, (_, attr, quote, rest) => `${attr}=${quote}${prefix}/${rest}${quote}`);
|
|
170
|
+
}
|
|
171
|
+
function rewriteLocationHeader(loc, parsed, mountPrefix) {
|
|
172
|
+
try {
|
|
173
|
+
const absUrl = new URL(loc);
|
|
174
|
+
// Same scheme + same host + same port → safe to rewrite. Different
|
|
175
|
+
// scheme on the same host (e.g. http page issuing https:// redirect)
|
|
176
|
+
// is treated as cross-target and left untouched.
|
|
177
|
+
const expectedProto = 'http:';
|
|
178
|
+
const sameProto = absUrl.protocol === expectedProto;
|
|
179
|
+
const sameHost = absUrl.hostname.toLowerCase() === parsed.host;
|
|
180
|
+
const samePort = Number(absUrl.port || 80) === parsed.port;
|
|
181
|
+
if (sameProto && sameHost && samePort) {
|
|
182
|
+
return `${mountPrefix}${absUrl.pathname}${absUrl.search}${absUrl.hash}`;
|
|
183
|
+
}
|
|
184
|
+
return loc;
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
if (loc.startsWith('/') && !loc.startsWith('//')) {
|
|
188
|
+
return `${mountPrefix}${loc}`;
|
|
189
|
+
}
|
|
190
|
+
return loc;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function parseCookieHeader(header, name) {
|
|
194
|
+
if (!header)
|
|
195
|
+
return null;
|
|
196
|
+
for (const part of header.split(';')) {
|
|
197
|
+
const [k, v] = part.trim().split('=');
|
|
198
|
+
if (k === name)
|
|
199
|
+
return decodeURIComponent(v ?? '');
|
|
200
|
+
}
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
function hasValidSessionCookie(req) {
|
|
204
|
+
const token = parseCookieHeader(req.headers['cookie'], COOKIE_NAME);
|
|
205
|
+
if (!token)
|
|
206
|
+
return false;
|
|
207
|
+
try {
|
|
208
|
+
const config = (0, config_1.getConfig)();
|
|
209
|
+
const decoded = jwt.verify(token, config.jwtSecret);
|
|
210
|
+
return decoded.typ === 'browser-proxy' && typeof decoded.username === 'string';
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Explicit-Bearer admin gate. Deliberately does NOT fall back to localhost
|
|
218
|
+
* auto-auth: any same-machine browser can blind-CSRF /_session if we trust
|
|
219
|
+
* the socket address, which would let a malicious page mint cookies and
|
|
220
|
+
* then drive arbitrary GETs through /api/browser-proxy/. Caller must
|
|
221
|
+
* present a real admin JWT (the frontend already has one via
|
|
222
|
+
* /api/auth/local-token or /api/auth/login).
|
|
223
|
+
*/
|
|
224
|
+
function requireBearerAdmin(req, res, next) {
|
|
225
|
+
const authHeader = req.headers['authorization'];
|
|
226
|
+
if (!authHeader?.startsWith('Bearer ')) {
|
|
227
|
+
res.status(401).json({ error: 'Bearer token required' });
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const user = (0, auth_1.verifyToken)(authHeader.slice(7));
|
|
231
|
+
if (!user || !(0, config_1.isAdminUser)(user.username)) {
|
|
232
|
+
res.status(403).json({ error: 'Admin only' });
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
req.user = user;
|
|
236
|
+
next();
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Issues a short-lived cookie that the iframe can present on subsequent
|
|
240
|
+
* GETs. The cookie is path-scoped to /api/browser-proxy/, HttpOnly,
|
|
241
|
+
* SameSite=Lax — so it travels with same-origin iframe requests but
|
|
242
|
+
* never leaves the daemon.
|
|
243
|
+
*/
|
|
244
|
+
router.post('/_session', requireBearerAdmin, (req, res) => {
|
|
245
|
+
const config = (0, config_1.getConfig)();
|
|
246
|
+
const token = jwt.sign({ username: req.user?.username, typ: 'browser-proxy' }, config.jwtSecret, { expiresIn: `${COOKIE_MAX_AGE_SEC}s` });
|
|
247
|
+
res.setHeader('Set-Cookie', `${COOKIE_NAME}=${encodeURIComponent(token)}; Path=/api/browser-proxy/; HttpOnly; SameSite=Lax; Max-Age=${COOKIE_MAX_AGE_SEC}`);
|
|
248
|
+
res.json({ ok: true, maxAge: COOKIE_MAX_AGE_SEC });
|
|
249
|
+
});
|
|
250
|
+
async function handle(req, res) {
|
|
251
|
+
// ONLY trust the cookie. Do not fall back to req.user — this route is
|
|
252
|
+
// mounted without authMiddleware specifically so that localhost
|
|
253
|
+
// auto-auth (or any CSRF-able header) cannot reach the proxy. Cookie
|
|
254
|
+
// can only be issued by /_session, which requires explicit Bearer admin.
|
|
255
|
+
if (!hasValidSessionCookie(req)) {
|
|
256
|
+
res.status(403).send('Browser proxy session required — call POST /_session first');
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const hostportRaw = req.params['hostport'];
|
|
260
|
+
if (!hostportRaw) {
|
|
261
|
+
res.status(400).send('hostport required');
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const parsed = parseHostport(hostportRaw);
|
|
265
|
+
if (!parsed) {
|
|
266
|
+
res.status(400).send('Invalid hostport (expected host:port, http only, ports 1-65535 except blocked)');
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
const resolvedIp = await resolveAllowedTarget(parsed.host);
|
|
270
|
+
if (!resolvedIp) {
|
|
271
|
+
res.status(403).send('Target not allowed — must resolve to RFC1918 / loopback (excluding cloud-metadata)');
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
// req.url is mount-relative: "/127.0.0.1:8080/foo/bar?x=1" or "/127.0.0.1:8080".
|
|
275
|
+
const afterMount = req.url.replace(/^\/+/, '');
|
|
276
|
+
const slashIdx = afterMount.indexOf('/');
|
|
277
|
+
const subPath = slashIdx >= 0 ? afterMount.slice(slashIdx) : '/';
|
|
278
|
+
// Fetch by resolved IP — pins the connection to the address we just
|
|
279
|
+
// validated, so DNS rebinding between validation and fetch is harmless.
|
|
280
|
+
const targetUrl = `http://${resolvedIp}:${parsed.port}${subPath}`;
|
|
281
|
+
const mountPrefix = `/api/browser-proxy/${hostportRaw}`;
|
|
282
|
+
try {
|
|
283
|
+
const upstream = await fetch(targetUrl, {
|
|
284
|
+
method: 'GET',
|
|
285
|
+
redirect: 'manual',
|
|
286
|
+
signal: AbortSignal.timeout(UPSTREAM_TIMEOUT_MS),
|
|
287
|
+
headers: {
|
|
288
|
+
// Send original hostname as Host so vhost-aware servers route correctly.
|
|
289
|
+
'Host': `${parsed.host}:${parsed.port}`,
|
|
290
|
+
'User-Agent': req.headers['user-agent'] || 'ccweb-browser-proxy',
|
|
291
|
+
'Accept': req.headers['accept'] || '*/*',
|
|
292
|
+
'Accept-Language': req.headers['accept-language'] || 'en',
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
const declaredLen = Number(upstream.headers.get('content-length') || '0');
|
|
296
|
+
if (declaredLen > MAX_PROXY_SIZE) {
|
|
297
|
+
res.status(413).send('Upstream response too large for proxy');
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
res.status(upstream.status);
|
|
301
|
+
upstream.headers.forEach((value, name) => {
|
|
302
|
+
const lower = name.toLowerCase();
|
|
303
|
+
if (STRIPPED_RESPONSE_HEADERS.has(lower))
|
|
304
|
+
return;
|
|
305
|
+
if (lower === 'location') {
|
|
306
|
+
res.setHeader('Location', rewriteLocationHeader(value, parsed, mountPrefix));
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
res.setHeader(name, value);
|
|
310
|
+
});
|
|
311
|
+
const contentType = upstream.headers.get('content-type') || '';
|
|
312
|
+
const isHtml = contentType.includes('text/html');
|
|
313
|
+
// Stream-aware cap: read in chunks, abort if we exceed limit before
|
|
314
|
+
// the whole body lands in memory. Compatible with chunked responses
|
|
315
|
+
// that don't declare Content-Length.
|
|
316
|
+
const chunks = [];
|
|
317
|
+
let total = 0;
|
|
318
|
+
if (upstream.body) {
|
|
319
|
+
const reader = upstream.body.getReader();
|
|
320
|
+
while (true) {
|
|
321
|
+
const { done, value } = await reader.read();
|
|
322
|
+
if (done)
|
|
323
|
+
break;
|
|
324
|
+
total += value.byteLength;
|
|
325
|
+
if (total > MAX_PROXY_SIZE) {
|
|
326
|
+
reader.cancel().catch(() => { });
|
|
327
|
+
if (!res.headersSent)
|
|
328
|
+
res.status(413);
|
|
329
|
+
res.end();
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
chunks.push(value);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
const buf = Buffer.concat(chunks.map((c) => Buffer.from(c)));
|
|
336
|
+
if (isHtml) {
|
|
337
|
+
res.setHeader('Content-Security-Policy', PROXY_HTML_CSP);
|
|
338
|
+
const rewritten = rewriteHtml(buf.toString('utf-8'), mountPrefix);
|
|
339
|
+
const out = Buffer.from(rewritten, 'utf-8');
|
|
340
|
+
res.setHeader('Content-Length', String(out.byteLength));
|
|
341
|
+
res.end(out);
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
res.setHeader('Content-Length', String(buf.byteLength));
|
|
345
|
+
res.end(buf);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
catch (err) {
|
|
349
|
+
const name = err?.name;
|
|
350
|
+
const reason = name === 'TimeoutError' ? 'Upstream timeout' : 'Upstream fetch failed';
|
|
351
|
+
log.warn({ err, targetUrl }, 'browser-proxy upstream error');
|
|
352
|
+
if (!res.headersSent) {
|
|
353
|
+
res.status(502).send(reason);
|
|
354
|
+
}
|
|
355
|
+
else if (!res.writableEnded) {
|
|
356
|
+
res.end();
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
router.get('/:hostport', handle);
|
|
361
|
+
router.get('/:hostport/*', handle);
|
|
362
|
+
exports.default = router;
|
|
363
|
+
//# sourceMappingURL=browser-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-proxy.js","sourceRoot":"","sources":["../../src/routes/browser-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{bH as e,bI as t,r as n,bJ as r,c as a,h as i,bK as o,aX as s,j as l,R as c,d as u,U as d,bL as p,t as m,b2 as g,B as h,A as f,q as b,bM as y,a as E,a8 as v,aa as S,a6 as w,a5 as k,a9 as x,a4 as T,bk as A,
|
|
1
|
+
import{bH as e,bI as t,r as n,bJ as r,c as a,h as i,bK as o,aX as s,j as l,R as c,d as u,U as d,bL as p,t as m,b2 as g,B as h,A as f,q as b,bM as y,a as E,a8 as v,aa as S,a6 as w,a5 as k,a9 as x,a4 as T,bk as A,aH as _,bz as I,bA as N,bB as R,i as C,bN as O,bO as L,s as D,bP as M,bQ as P,bC as F,bR as B,bE as U,bF as z,S as $,l as G,p as j}from"./index-nYsy3LMF.js";import{C as H}from"./chevron-down-B3q2CU-d.js";import{a as q,C as V,u as W,c as Y}from"./index-DsYny3RQ.js";function K(){!e.current&&t();const[a]=n.useState(r.current);return a}
|
|
2
2
|
/**
|
|
3
3
|
* @license lucide-react v0.309.0 - ISC
|
|
4
4
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as e,r as t,b as n,j as i,U as r,B as o,m as a}from"./index-
|
|
1
|
+
import{c as e,r as t,b as n,j as i,U as r,B as o,m as a}from"./index-nYsy3LMF.js";import{Z as l,a as s}from"./ProjectPage-tcwSSEFX.js";import"./purify.es-CgRAQgUo.js";import"./ChatOverlay-W-pSFHsV.js";import"./chevron-down-B3q2CU-d.js";import"./index-DsYny3RQ.js";import"./select-BOLkADQv.js";import"./search-B9B3Cq4V.js";
|
|
2
2
|
/**
|
|
3
3
|
* @license lucide-react v0.309.0 - ISC
|
|
4
4
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/OfficePreview-
|
|
2
|
-
import{c as e,
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/OfficePreview-DY-ew_ex.js","assets/index-nYsy3LMF.js","assets/index-B55CtERr.css","assets/purify.es-CgRAQgUo.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{c as e,aI as t,br as s,aK as a,r as n,bs as r,bt as l,j as o,bu as c,m as i,d,bv as u,bw as x,bx as m,by as h,bz as p,bA as f,bB as g,ak as b,aj as j,bC as v,bD as y,t as N,ai as w,aD as k,bE as C,U as S,bF as I,a as P,b as z,g as M,D as U,h as T,R as A,_ as E,l as D,X as $,p as L,aV as R,bG as _,C as F,A as H,q as O}from"./index-nYsy3LMF.js";import{A as q,g as W,i as B,T as V,j as K,k as G,G as J,M as Q,r as X,a as Y,b as Z,c as ee,e as te,h as se,o as ae,d as ne,I as re,F as le}from"./ChatOverlay-W-pSFHsV.js";import{a as oe}from"./index-DsYny3RQ.js";import{C as ce}from"./chevron-down-B3q2CU-d.js";
|
|
3
3
|
/**
|
|
4
4
|
* @license lucide-react v0.309.0 - ISC
|
|
5
5
|
*
|
|
@@ -11,4 +11,4 @@ import{c as e,aH as t,br as s,aJ as a,r as n,bs as r,bt as l,j as o,bu as c,m as
|
|
|
11
11
|
*
|
|
12
12
|
* This source code is licensed under the ISC license.
|
|
13
13
|
* See the LICENSE file in the root directory of this source tree.
|
|
14
|
-
*/function he({onSelectProject:e}){const h=t(),p=s(e=>e.clearToken),{projects:f,fetchProjects:g,hasFetched:b,loading:j}=a(),v=n.useCallback(()=>{a.getState().setProjects([]),p(),h("/login")},[p,h]),[y,N]=n.useState(new Map),[w,k]=n.useState(new Set),[C,S]=n.useState(!1);n.useEffect(()=>{g()},[g]);const I=n.useCallback(e=>{e.status&&N(t=>{const s=new Map(t);return s.set(e.projectId,e.status),s}),void 0!==e.active&&k(t=>{const s=new Set(t);return e.active?s.add(e.projectId):s.delete(e.projectId),s})},[]);r({onActivityUpdate:I});const{applyOrder:P}=l(),z=P(f.filter(e=>!e.archived));return o.jsxs("div",{className:"flex flex-col h-full",children:[o.jsxs("div",{className:"flex items-center gap-3 px-4 h-12 border-b border-border shrink-0",children:[o.jsx("span",{className:"font-semibold text-base flex-1",children:"CC Web"}),o.jsx(c,{}),o.jsx("button",{onClick:()=>{(async()=>{S(!0);try{await g()}finally{S(!1)}})()},className:"text-muted-foreground active:text-foreground",disabled:C,"aria-label":"Refresh",children:o.jsx(i,{className:d("h-4 w-4",C&&"animate-spin")})}),o.jsx("button",{onClick:()=>h("/settings"),className:"text-muted-foreground active:text-foreground","aria-label":"Settings",children:o.jsx(u,{className:"h-4 w-4"})}),o.jsx("button",{onClick:v,className:"text-muted-foreground active:text-foreground","aria-label":"Logout",children:o.jsx(x,{className:"h-4 w-4"})}),!me&&o.jsx("button",{onClick:()=>h("/"),className:"text-muted-foreground active:text-foreground","aria-label":"Desktop mode",children:o.jsx(m,{className:"h-4 w-4"})})]}),o.jsxs("div",{className:"flex-1 overflow-y-auto px-3 py-3",children:[j&&!b&&o.jsx("div",{className:"text-center text-muted-foreground text-sm py-12",children:"加载中..."}),b&&0===z.length&&o.jsx("div",{className:"text-center text-muted-foreground text-sm py-12",children:"暂无项目"}),o.jsx("div",{className:"grid grid-cols-2 gap-2",children:z.map(t=>{var s;const a="running"===(s=t,y.get(s.id)??s.status??"stopped"),n=w.has(t.id),r=o.jsxs("button",{onClick:()=>e(t.id),className:d("w-full text-left rounded-xl border bg-card p-2.5 active:bg-accent transition-colors",n?"border-transparent":"border-border"),children:[o.jsxs("div",{className:"flex items-center gap-1.5 mb-1",children:[o.jsx("span",{className:d("w-2 h-2 rounded-full shrink-0",a?"bg-green-500":"bg-zinc-400")}),o.jsx("span",{className:"font-medium text-sm truncate flex-1",children:t.name})]}),o.jsx("div",{className:"text-[10px] text-muted-foreground font-mono truncate",children:t.cliTool??"claude"})]});return o.jsx("div",{className:n?"card-active-glow rounded-xl":void 0,children:r},t.id)})})]})]})}function pe(e){if(!e.phase)return null;if("thinking"===e.phase)return"思考中";if("tool_result"===e.phase)return"处理结果";if("tool_use"===e.phase){const t=(e.detail||"").toLowerCase();return"bash"===t?"执行命令":"read"===t?"读取文件":"edit"===t||"multiedit"===t?"编辑文件":"write"===t?"写入文件":"grep"===t?"搜索内容":"glob"===t?"匹配文件":"webfetch"===t||"websearch"===t?"访问网络":"task"===t?"调度子任务":"todowrite"===t?"更新任务列表":"notebookedit"===t?"编辑 Notebook":e.detail?`调用 ${e.detail}`:"调用工具"}return null}function fe({project:e,onBack:t,onOpenPanel:s,onContextUpdate:a}){const[r,l]=n.useState(""),c=n.useRef(null),i=n.useRef(null),[u,x]=n.useState([]),m=n.useCallback(e=>{x(t=>{const s=[...t,e];return s.length>200?s.slice(-200):s})},[]),P=n.useRef(null),z=n.useCallback(e=>{var t;"stopped"===e&&(null==(t=P.current)||t.call(P,"stopped"))},[]),[M,U]=n.useState(null);n.useEffect(()=>{const t=t=>{const s=t.detail;s&&s.projectId===e.id&&("cli_prompt_detected"===s.type?U({kind:s.kind,label:s.label,detectedAt:s.detectedAt,options:s.options}):"cli_prompt_dismissed"===s.type&&U(e=>(null==e?void 0:e.kind)===s.kind?null:e))};return window.addEventListener("ccweb:cli-prompt-msg",t),()=>window.removeEventListener("ccweb:cli-prompt-msg",t)},[e.id]);const[T,A]=n.useState([]),E=n.useRef(new Set),$=n.useCallback(e=>{E.current.has(e.toolUseId)||A(t=>t.some(t=>t.toolUseId===e.toolUseId)?t:[...t,{projectId:e.projectId,toolUseId:e.toolUseId,toolName:e.toolName,toolInput:e.toolInput,sessionId:e.sessionId,createdAt:e.createdAt}])},[]),D=n.useCallback(e=>{E.current.add(e.toolUseId),A(t=>t.filter(t=>t.toolUseId!==e.toolUseId))},[]),L=n.useCallback(e=>{E.current.add(e),A(t=>t.filter(t=>t.toolUseId!==e))},[]),[R,_]=n.useState(null),H=n.useRef(0),F=n.useCallback(e=>{var t,s,a;if(!e.active)return void _(null);if("text"===(null==(t=e.semantic)?void 0:t.phase))return void _(null);const n=null==(s=e.semantic)?void 0:s.phase,r=null==(a=e.semantic)?void 0:a.detail;_(e=>e?e.phase===n&&e.detail===r?e:{...e,phase:n,detail:r}:{id:"mab"+ ++H.current,phase:n,detail:r})},[]),{sendInput:O,connected:Q}=h({projectId:e.id,enabled:!0,onChatMessage:m,onStatusChange:z,onContextUpdate:a,onApprovalRequest:$,onApprovalResolved:D,onSemanticUpdate:F});n.useEffect(()=>{let t=!1;if(U(null),Q)return p(e.id).then(e=>{!t&&e.active&&U({kind:e.active.kind,label:e.active.label,detectedAt:e.active.detectedAt,options:e.active.options})}).catch(()=>{}),()=>{t=!0}},[e.id,Q]),n.useEffect(()=>{if(!Q)return;if("claude"!==e.cliTool)return;let t=!1;return f(e.id).then(e=>{if(t)return;const s=e.pending.filter(e=>!E.current.has(e.toolUseId));A(e=>{const t=new Map;for(const a of s)t.set(a.toolUseId,a);for(const s of e)t.has(s.toolUseId)||E.current.has(s.toolUseId)||t.set(s.toolUseId,s);return[...t.values()]})}).catch(()=>{}),()=>{t=!0}},[e.id,e.cliTool,Q]);const{state:X,setState:Y,messages:Z,hasMoreHistory:ee,loadMoreHistory:te,sendMessage:se,isWaking:ae}=g({project:e,liveMessages:u,ws:{send:O,connected:Q},historyLimit:20});P.current=Y;const ne=n.useRef(Q);n.useEffect(()=>{!ne.current&&Q&&x([]),ne.current=Q},[Q]);const re=(()=>{for(let e=Z.length-1;e>=0;e--)if("assistant"===Z[e].role)return e;return-1})(),[le,de]=n.useState([]),[ue,me]=n.useState([]),[he,fe]=n.useState(null),[ge,be]=n.useState(null),je=n.useRef(!1);n.useEffect(()=>{b().then(de).catch(()=>{}),j(e.id).then(me).catch(()=>{})},[e.id]);const ve=n.useCallback(e=>{const t=i.current;if(!t)return void l(t=>t+e);const s=t.selectionStart??r.length,a=t.selectionEnd??r.length,n=r.slice(0,s)+e+r.slice(a);l(n),requestAnimationFrame(()=>{t.focus();const a=s+e.length;t.setSelectionRange(a,a),t.style.height="auto",t.style.height=Math.min(t.scrollHeight,128)+"px"})},[r]),ye=n.useCallback(e=>{fe(null),ve(e+" ")},[ve]),Ne=n.useCallback(t=>{const s=e.folderPath;let a=t;s&&(t===s||t.startsWith(s+"/")||t.startsWith(s+"\\"))&&(a=t.slice(s.length).replace(/^[/\\]+/,"")),fe(null),ve(`@${a} `)},[e.folderPath,ve]),we=n.useCallback(async()=>{if("skills"!==he){if(!je.current){je.current=!0;try{const t=await v(e.cliTool??"claude",e.id);be(t)}catch{be({builtin:[],custom:[],plugins:[],mcp:[]})}finally{je.current=!1}}fe("skills")}else fe(null)},[he,e.cliTool,e.id]),ke=n.useCallback(async()=>{const e=c.current,t=(null==e?void 0:e.scrollHeight)??0;await te(),requestAnimationFrame(()=>{e&&(e.scrollTop+=e.scrollHeight-t)})},[te]),Ce=n.useRef(0);n.useEffect(()=>{const e=c.current;if(!e)return;const t=Z.length>Ce.current,s=0===Ce.current&&Z.length>0;Ce.current=Z.length,s?e.scrollTo({top:e.scrollHeight}):t&&e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},[Z,T.length]);const[Se,Ie]=n.useState(!1),Pe=n.useCallback(async()=>{const e=r.trim();if(!e||Se)return;Ie(!0);const t=await se(e);Ie(!1),"delivered"===t&&(l(""),i.current&&(i.current.style.height="auto"))},[r,Se,se]),ze=y(Pe,"shift"),Me=n.useCallback(async(t,s)=>{fe(null);try{"failed"===await se(t.command)?N.error("快捷命令未送达,请重试或检查会话"):"project"===s&&w(e.id,t.id,!0).catch(e=>{console.error("Failed to mark shortcut used:",e)})}catch(a){console.error("Shortcut send error:",a),N.error("快捷命令发送失败")}},[se,e.id]),Ue="live"===X;return o.jsxs("div",{className:"flex flex-col h-full bg-background",children:[o.jsxs("div",{className:"flex items-center gap-2 px-3 h-12 border-b border-border shrink-0",children:[o.jsx("button",{onClick:t,className:"text-muted-foreground active:text-foreground p-1",children:o.jsx(k,{className:"h-5 w-5"})}),o.jsxs("div",{className:"flex items-center gap-1.5 flex-1 min-w-0",children:[o.jsx("span",{className:"font-medium text-sm truncate",children:e.name}),o.jsx("span",{className:d("w-2 h-2 rounded-full shrink-0",Ue?"bg-green-500":ae?"bg-yellow-400 animate-pulse":"bg-zinc-400")})]}),o.jsx("button",{onClick:s,className:"text-muted-foreground active:text-foreground p-1",children:o.jsx(xe,{className:"h-5 w-5"})})]}),o.jsxs("div",{ref:c,className:"flex-1 overflow-y-auto px-3 py-3 space-y-3 min-h-0",children:[ee&&o.jsx("div",{className:"flex justify-center pb-1",children:o.jsxs("button",{onClick:()=>{ke()},className:"flex items-center gap-1 px-3 py-1.5 rounded-full text-xs text-muted-foreground border border-border active:bg-accent transition-colors",children:[o.jsx(oe,{className:"h-3 w-3"}),"加载更早消息"]})}),Z.map((e,t)=>{const s="user"===e.role;return o.jsx("div",{className:d("flex",s?"justify-end":"justify-start"),children:o.jsx("div",{className:d("max-w-[85%] rounded-xl px-3 py-2 break-words text-sm leading-relaxed",s?"bg-blue-500/15 text-foreground border border-blue-500/20 rounded-br-sm whitespace-pre-wrap":"bg-secondary text-secondary-foreground border border-border rounded-bl-sm"),children:s?e.content:o.jsx(q,{content:e.content,blocks:e.blocks,isLatest:t===re})})},e.id)}),T.map(e=>o.jsx(W,{approval:e,onResolved:L},e.toolUseId)),M&&o.jsx(B,{prompt:M,onSelect:async t=>{await C(e.id,t)}}),R&&0===T.length&&o.jsx("div",{className:"flex justify-start",children:o.jsxs("div",{className:"rounded-2xl rounded-bl-md px-3 py-1.5 bg-black/5 dark:bg-white/10 border border-black/10 dark:border-white/15 flex items-center gap-2 text-xs text-muted-foreground",children:[o.jsx(V,{}),pe(R)&&o.jsx("span",{children:pe(R)})]})},R.id),0===Z.length&&0===T.length&&!R&&"stopped"===X&&o.jsx("div",{className:"flex items-center justify-center h-full text-muted-foreground/40 text-sm",children:"暂无对话记录"}),ae&&o.jsx("div",{className:"flex items-center justify-center py-4 text-yellow-400 text-sm animate-pulse",children:"启动中..."})]}),"global"===he||"project"===he?o.jsx("div",{className:"border-t border-border max-h-48 overflow-y-auto shrink-0",children:o.jsxs("div",{className:"px-3 py-2 space-y-1",children:[("global"===he?le:ue).map(e=>o.jsxs("button",{onClick:()=>Me(e,he),disabled:ae,className:d("w-full text-left rounded-md px-2.5 py-2 text-sm active:bg-accent transition-colors border border-border/50",ae&&"opacity-50 cursor-not-allowed"),children:[o.jsx("div",{className:"font-medium text-xs",children:e.label}),o.jsx("div",{className:"text-[11px] text-muted-foreground font-mono truncate",children:e.command})]},e.id)),0===("global"===he?le:ue).length&&o.jsx("div",{className:"text-center text-muted-foreground text-xs py-3",children:"暂无快捷 Prompts"})]})}):"skills"===he&&ge?o.jsx("div",{className:"border-t border-border shrink-0",children:o.jsx(K,{data:ge,onCommand:ye})}):"files"===he&&e.folderPath?o.jsx("div",{className:"border-t border-border shrink-0",children:o.jsx(G,{projectPath:e.folderPath,onSelect:Ne})}):null,o.jsxs("div",{className:"flex items-center gap-1.5 px-3 py-1.5 border-t border-border shrink-0",children:[o.jsx("button",{onClick:()=>{we()},title:"斜杠命令",className:d("flex items-center justify-center w-7 h-7 rounded font-mono text-base transition-colors","skills"===he?"bg-accent text-foreground font-medium":"text-muted-foreground active:bg-accent"),children:"/"}),o.jsx("button",{onClick:()=>fe(e=>"files"===e?null:"files"),disabled:!e.folderPath,title:"引用文件",className:d("flex items-center justify-center w-7 h-7 rounded font-mono text-base transition-colors","files"===he?"bg-accent text-foreground font-medium":e.folderPath?"text-muted-foreground active:bg-accent":"text-muted-foreground/30 cursor-not-allowed"),children:"@"}),le.length>0&&o.jsxs("button",{onClick:()=>fe(e=>"global"===e?null:"global"),className:d("flex items-center gap-1 px-2 py-1 rounded-md text-xs transition-colors","global"===he?"bg-accent text-foreground font-medium":"text-muted-foreground active:bg-accent"),children:[o.jsx(J,{className:"h-3 w-3"}),"全局","global"===he&&o.jsx(ce,{className:"h-3 w-3"})]}),ue.length>0&&o.jsxs("button",{onClick:()=>fe(e=>"project"===e?null:"project"),className:d("flex items-center gap-1 px-2 py-1 rounded-md text-xs transition-colors","project"===he?"bg-accent text-foreground font-medium":"text-muted-foreground active:bg-accent"),children:[o.jsx(ie,{className:"h-3 w-3"}),"项目","project"===he&&o.jsx(ce,{className:"h-3 w-3"})]})]}),o.jsx("div",{className:"border-t border-border px-3 py-2 shrink-0",style:{paddingBottom:"max(0.5rem, env(safe-area-inset-bottom))"},children:o.jsxs("div",{className:"flex items-end gap-2",children:[o.jsx("textarea",{ref:i,value:r,onChange:e=>l(e.target.value),onKeyDown:ze,disabled:ae||Se,placeholder:ae?"启动中...":Se?"发送中…":"stopped"===X?"输入消息(自动启动)...":"输入消息...",rows:1,className:d("flex-1 resize-none rounded-md border border-input bg-transparent px-3 py-2 text-sm outline-none","focus:ring-1 focus:ring-ring placeholder:text-muted-foreground/50","max-h-32 overflow-y-auto",(ae||Se)&&"opacity-50 cursor-not-allowed"),style:{minHeight:"2.5rem"},onInput:e=>{const t=e.currentTarget;t.style.height="auto",t.style.height=Math.min(t.scrollHeight,128)+"px"}}),o.jsx("button",{onClick:Pe,disabled:ae||Se||!r.trim(),className:d("shrink-0 p-2 rounded-md transition-colors",r.trim()&&!Se?"text-blue-500 active:bg-blue-500/10":"text-muted-foreground/30"),children:Se?o.jsx(S,{className:"h-5 w-5 animate-spin"}):o.jsx(I,{className:"h-5 w-5"})})]})})]})}const ge=A.lazy(()=>E(()=>import("./OfficePreview-CcNfdvDk.js"),__vite__mapDeps([0,1,2,3])).then(e=>({default:e.OfficePreview}))),be=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","ico","avif"]),je=new Set(["docx","xlsx","xls","pptx"]),ve={js:"javascript",jsx:"jsx",ts:"typescript",tsx:"tsx",py:"python",rb:"ruby",go:"go",rs:"rust",java:"java",kt:"kotlin",swift:"swift",c:"c",cpp:"cpp",h:"c",cs:"csharp",php:"php",sh:"bash",bash:"bash",zsh:"bash",yaml:"yaml",yml:"yaml",json:"json",toml:"toml",html:"html",htm:"html",xml:"xml",svg:"xml",css:"css",scss:"scss",less:"less",sql:"sql",graphql:"graphql",gql:"graphql",dockerfile:"docker",makefile:"makefile",r:"r",lua:"lua",dart:"dart",zig:"zig"};function ye(e){return e.split("/").pop()??e}function Ne({filePath:e,onBack:t}){const[s,a]=n.useState(null),[r,l]=n.useState(!0),[c,i]=n.useState(null),{resolved:d}=P(),u=function(e){const t=e.split("/").pop()??"",s=t.toLowerCase();if("dockerfile"===s)return"dockerfile";if("makefile"===s)return"makefile";const a=t.lastIndexOf(".");return a>=0?t.slice(a+1).toLowerCase():""}(e),x=be.has(u),m=je.has(u),h=ve[u],p="dark"===d;n.useEffect(()=>{x||m?l(!1):(l(!0),i(null),z(e).then(a).catch(e=>i(e instanceof Error?e.message:"Failed to load")).finally(()=>l(!1)))},[e,x,m]);const f=T(e),g=n.useMemo(()=>{const e=M();return e?`${f}&token=${encodeURIComponent(e)}`:f},[f]),b=n.useMemo(()=>x?`${g}&t=${Date.now()}`:"",[g,x]);return o.jsxs("div",{className:"flex flex-col h-full",children:[o.jsxs("div",{className:"flex items-center gap-2 px-3 h-12 border-b border-border shrink-0",children:[o.jsx("button",{onClick:t,className:"text-muted-foreground active:text-foreground p-1",children:o.jsx(k,{className:"h-5 w-5"})}),o.jsx("span",{className:"flex-1 text-sm font-medium truncate",children:ye(e)}),o.jsx("a",{href:g,download:!0,className:"text-muted-foreground active:text-foreground p-1",onClick:e=>e.stopPropagation(),children:o.jsx(U,{className:"h-4 w-4"})})]}),o.jsxs("div",{className:"flex-1 overflow-auto min-h-0",children:[r&&o.jsx("div",{className:"flex items-center justify-center py-12",children:o.jsx(S,{className:"h-5 w-5 animate-spin text-muted-foreground"})}),c&&o.jsx("div",{className:"text-center text-destructive text-sm py-12 px-4",children:c}),x&&o.jsx("div",{className:"flex items-center justify-center p-4 h-full",children:o.jsx("img",{src:b,alt:ye(e),className:"max-w-full max-h-full object-contain rounded",style:{touchAction:"pinch-zoom"}})}),m&&o.jsx(n.Suspense,{fallback:o.jsx("div",{className:"flex items-center justify-center py-12",children:o.jsx(S,{className:"h-5 w-5 animate-spin text-muted-foreground"})}),children:o.jsx(ge,{filePath:e,ext:u,zoom:100})}),s&&(s.binary||s.tooLarge)&&o.jsxs("div",{className:"text-center py-12 px-4 space-y-3",children:[o.jsxs("p",{className:"text-muted-foreground text-sm",children:[s.binary?"二进制文件":"文件过大",s.size>0&&` (${j=s.size,j<1024?`${j} B`:j<1048576?`${(j/1024).toFixed(1)} KB`:`${(j/1048576).toFixed(1)} MB`})`]}),o.jsxs("a",{href:g,download:!0,className:"inline-flex items-center gap-1.5 text-sm text-blue-500 active:text-blue-400",children:[o.jsx(U,{className:"h-4 w-4"}),"下载文件"]})]}),s&&!s.binary&&!s.tooLarge&&null!=s.content&&o.jsxs(o.Fragment,{children:["md"===u&&o.jsx("div",{className:"prose prose-sm dark:prose-invert max-w-none px-4 py-3",children:o.jsx(Q,{remarkPlugins:[Y,Z],rehypePlugins:[X],urlTransform:(e,t,s)=>"src"===t&&"img"===s.tagName?e:te(e),components:{img:({src:t,alt:s,...a})=>o.jsx("img",{...a,src:ee(e,t,M()),alt:s??"",loading:"lazy",style:{maxWidth:"100%",height:"auto"}})},children:s.content})}),"md"!==u&&h&&o.jsx(se,{language:h,style:p?ae:ne,customStyle:{margin:0,fontSize:"12px",borderRadius:0},showLineNumbers:!0,children:s.content}),"md"!==u&&!h&&o.jsx("pre",{className:"p-4 text-xs font-mono whitespace-pre-wrap break-words",children:s.content})]})]})]});var j}const we=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","ico","avif"]),ke=new Set(["js","jsx","ts","tsx","py","rb","go","rs","java","c","cpp","h","swift","kt","cs","php","sh","bash","zsh","r","lua","dart","zig","css","scss","less","html","htm","xml","sql"]),Ce=new Set(["json","yaml","yml","toml","csv","tsv"]);function Se({entry:e}){if("dir"===e.type)return o.jsx(L,{className:"h-8 w-8 text-blue-400"});const t=function(e){const t=e.lastIndexOf(".");return t>=0?e.slice(t+1).toLowerCase():""}(e.name);return we.has(t)?o.jsx(re,{className:"h-8 w-8 text-emerald-400"}):ke.has(t)?o.jsx(de,{className:"h-8 w-8 text-orange-400"}):Ce.has(t)?o.jsx(ue,{className:"h-8 w-8 text-yellow-400"}):"md"===t?o.jsx(le,{className:"h-8 w-8 text-sky-400"}):o.jsx(R,{className:"h-8 w-8 text-muted-foreground"})}function Ie({rootPath:e,onClose:t}){const[s,a]=n.useState(e),[r,l]=n.useState([]),[c,i]=n.useState(!0),[d,u]=n.useState(null),x=n.useCallback(async e=>{i(!0);try{const t=[...(await $(e)).entries].sort((e,t)=>e.type!==t.type?"dir"===e.type?-1:1:e.name.localeCompare(t.name));l(t),a(e)}catch{l([])}finally{i(!1)}},[]);n.useEffect(()=>{x(e)},[e,x]);const m=s!==e,h=s.startsWith(e)?s.slice(e.length)||"/":s;return d?o.jsx(Ne,{filePath:d,onBack:()=>u(null)}):o.jsxs("div",{className:"flex flex-col h-full",children:[o.jsxs("div",{className:"flex items-center gap-2 px-3 h-12 border-b border-border shrink-0",children:[o.jsx("button",{onClick:t,className:"text-muted-foreground active:text-foreground p-1",children:o.jsx(D,{className:"h-5 w-5"})}),o.jsxs("div",{className:"flex items-center gap-1 flex-1 min-w-0 text-sm",children:[m&&o.jsx("button",{onClick:()=>{if(s===e)return;const t=s.replace(/\/[^/]+$/,"")||"/";t.startsWith(e)&&x(t)},className:"text-muted-foreground active:text-foreground p-0.5 shrink-0",children:o.jsx(k,{className:"h-4 w-4"})}),o.jsx("span",{className:"truncate text-muted-foreground font-mono text-xs",children:h})]})]}),o.jsxs("div",{className:"flex-1 overflow-y-auto px-3 py-3",children:[c&&o.jsx("div",{className:"flex items-center justify-center py-12",children:o.jsx(S,{className:"h-5 w-5 animate-spin text-muted-foreground"})}),!c&&0===r.length&&o.jsx("div",{className:"text-center text-muted-foreground text-sm py-12",children:"空目录"}),!c&&o.jsx("div",{className:"grid grid-cols-3 gap-1",children:r.map(e=>o.jsxs("button",{onClick:()=>(e=>{"dir"===e.type?x(e.path):u(e.path)})(e),className:"flex flex-col items-center gap-1 p-2 rounded-md active:bg-accent transition-colors",children:[o.jsx(Se,{entry:e}),o.jsx("span",{className:"text-[11px] text-center leading-tight w-full line-clamp-2 break-all",children:e.name})]},e.path))})]})]})}function Pe(e){return e<50?"text-green-400":e<80?"text-yellow-400":"text-red-400"}function ze(e){return e<50?"bg-green-500":e<80?"bg-yellow-500":"bg-red-500"}function Me({projectName:e,cliTool:t,folderPath:s,contextData:a,onClose:r}){const[l,c]=n.useState(new Set(["context","usage","files"])),[u,x]=n.useState(null),[m,h]=n.useState(!1),p=e=>{c(t=>{const s=new Set(t);return s.has(e)?s.delete(e):s.add(e),s})};n.useEffect(()=>{h(!0),_(t).then(x).catch(()=>x(null)).finally(()=>h(!1))},[t]);const f=a?Math.round(a.usedPercentage):null;return o.jsxs("div",{className:"flex flex-col h-full",children:[o.jsxs("div",{className:"flex items-center gap-2 px-3 h-12 border-b border-border shrink-0",children:[o.jsx("button",{onClick:r,className:"text-muted-foreground active:text-foreground p-1",children:o.jsx(D,{className:"h-5 w-5"})}),o.jsx("span",{className:"flex-1 font-medium text-sm truncate",children:e})]}),o.jsxs("div",{className:"flex-1 overflow-y-auto",children:[o.jsxs("button",{onClick:()=>p("context"),className:"w-full flex items-center gap-2 px-4 py-2.5 border-b border-border/50 active:bg-accent",children:[l.has("context")?o.jsx(ce,{className:"h-3.5 w-3.5 text-muted-foreground"}):o.jsx(H,{className:"h-3.5 w-3.5 text-muted-foreground"}),o.jsx("span",{className:"text-sm font-medium",children:"上下文"}),null!==f&&o.jsxs("span",{className:d("text-xs font-mono ml-auto",Pe(f)),children:[f,"%"]})]}),l.has("context")&&o.jsx("div",{className:"px-4 py-3 border-b border-border/50",children:null!==f&&a?o.jsxs("div",{className:"space-y-2",children:[o.jsxs("div",{className:"flex items-center gap-2",children:[o.jsx("div",{className:"flex-1 h-2 bg-secondary rounded-full overflow-hidden",children:o.jsx("div",{className:d("h-full rounded-full transition-all",ze(f)),style:{width:`${Math.min(f,100)}%`}})}),o.jsxs("span",{className:d("text-xs font-mono w-10 text-right",Pe(f)),children:[f,"%"]})]}),o.jsxs("div",{className:"grid grid-cols-2 gap-x-4 gap-y-1 text-[11px] text-muted-foreground",children:[o.jsx("span",{children:"窗口大小"}),o.jsx("span",{className:"text-right font-mono",children:a.contextWindowSize>=1e6?`${(a.contextWindowSize/1e6).toFixed(1)}M`:`${Math.round(a.contextWindowSize/1e3)}K`}),o.jsx("span",{children:"输入 tokens"}),o.jsx("span",{className:"text-right font-mono",children:a.inputTokens.toLocaleString()}),o.jsx("span",{children:"输出 tokens"}),o.jsx("span",{className:"text-right font-mono",children:a.outputTokens.toLocaleString()})]})]}):o.jsx("div",{className:"text-xs text-muted-foreground/50 text-center py-2",children:"暂无数据"})}),o.jsxs("div",{className:"w-full flex items-center gap-2 px-4 py-2.5 border-b border-border/50 cursor-pointer",role:"button",tabIndex:0,onClick:()=>p("usage"),onKeyDown:e=>{"Enter"!==e.key&&" "!==e.key||p("usage")},children:[l.has("usage")?o.jsx(ce,{className:"h-3.5 w-3.5 text-muted-foreground"}):o.jsx(H,{className:"h-3.5 w-3.5 text-muted-foreground"}),o.jsx("span",{className:"text-sm font-medium",children:"用量"}),o.jsx("button",{onClick:e=>{e.stopPropagation(),(async()=>{h(!0);try{const{refreshUsage:e}=await E(async()=>{const{refreshUsage:e}=await import("./index-Bf5BlYFK.js").then(e=>e.bU);return{refreshUsage:e}},__vite__mapDeps([1,2]));x(await e(t))}catch{}finally{h(!1)}})()},className:"ml-auto text-muted-foreground active:text-foreground",children:o.jsx(i,{className:d("h-3 w-3",m&&"animate-spin")})})]}),l.has("usage")&&o.jsx("div",{className:"px-4 py-3 border-b border-border/50",children:u?o.jsxs("div",{className:"space-y-2",children:[u.planName&&o.jsxs("div",{className:"text-[11px] text-muted-foreground",children:["Plan: ",o.jsx("span",{className:"font-medium text-foreground",children:u.planName})]}),o.jsx(Ue,{label:"5h",bucket:u.fiveHour}),o.jsx(Ue,{label:"7d",bucket:u.sevenDay}),u.sevenDaySonnet&&o.jsx(Ue,{label:"7d Sonnet",bucket:u.sevenDaySonnet}),u.sevenDayOpus&&o.jsx(Ue,{label:"7d Opus",bucket:u.sevenDayOpus}),!u.fiveHour&&!u.sevenDay&&o.jsx("div",{className:"text-xs text-muted-foreground/50 text-center",children:"暂无数据"})]}):o.jsx("div",{className:"text-xs text-muted-foreground/50 text-center py-2",children:m?"加载中...":"暂无数据"})}),o.jsxs("button",{onClick:()=>p("files"),className:"w-full flex items-center gap-2 px-4 py-2.5 border-b border-border/50 active:bg-accent",children:[l.has("files")?o.jsx(ce,{className:"h-3.5 w-3.5 text-muted-foreground"}):o.jsx(H,{className:"h-3.5 w-3.5 text-muted-foreground"}),o.jsx("span",{className:"text-sm font-medium",children:"文件"})]}),l.has("files")&&o.jsx("div",{className:"h-[60vh]",children:o.jsx(Ie,{rootPath:s,onClose:()=>p("files")})})]})]})}function Ue({label:e,bucket:t}){if(!t||void 0===t.utilization)return null;const s=t.utilization,a=function(e){if(!e)return"";const t=new Date(e).getTime()-Date.now();if(t<=0)return"即将重置";const s=Math.floor(t/36e5),a=Math.floor(t%36e5/6e4);return s>0?`${s}h${a}m`:`${a}m`}(t.resetAt);return o.jsxs("div",{className:"flex items-center gap-2",children:[o.jsx("span",{className:"text-xs text-muted-foreground w-16",children:e}),o.jsx("div",{className:"flex-1 h-1.5 bg-secondary rounded-full overflow-hidden",children:o.jsx("div",{className:d("h-full rounded-full",ze(s)),style:{width:`${Math.min(s,100)}%`}})}),o.jsxs("span",{className:d("text-xs font-mono w-8 text-right",Pe(s)),children:[s,"%"]}),a&&o.jsx("span",{className:"text-[10px] text-muted-foreground/60",children:a})]})}function Te(){n.useEffect(()=>{const e=document.querySelector('meta[name="viewport"]');if(!e)return;const t=e.getAttribute("content")??"";return e.setAttribute("content","width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"),()=>{e.setAttribute("content",t)}},[]);const[e,t]=n.useState({screen:"list"}),[s,r]=n.useState(null),l=a(e=>e.projects),c=n.useCallback(e=>{t({screen:"chat",projectId:e}),r(null)},[]),i=n.useCallback(e=>{t({screen:"panel",projectId:e})},[]),d=n.useCallback(()=>{t(e=>"panel"===e.screen?{screen:"chat",projectId:e.projectId}:{screen:"list"})},[]),u="list"!==e.screen?l.find(t=>t.id===e.projectId):void 0;return o.jsxs("div",{className:"fixed inset-0 bg-background overflow-hidden",children:[o.jsxs(F,{mode:"wait",children:["list"===e.screen&&o.jsx(O.div,{className:"absolute inset-0",initial:{opacity:0},animate:{opacity:1},exit:{x:"-30%",opacity:0},transition:{duration:.2},style:{paddingTop:"env(safe-area-inset-top)"},children:o.jsx(he,{onSelectProject:c})},"list"),"chat"===e.screen&&u&&o.jsx(O.div,{className:"absolute inset-0",initial:{x:"100%"},animate:{x:0},exit:{x:"100%"},transition:{type:"tween",duration:.25},style:{paddingTop:"env(safe-area-inset-top)"},children:o.jsx(fe,{project:u,onBack:d,onOpenPanel:()=>i(e.projectId),onContextUpdate:r})},`chat-${e.projectId}`)]}),o.jsx(F,{children:"panel"===e.screen&&u&&o.jsx(O.div,{className:"absolute inset-0 z-50 bg-background",initial:{x:"100%"},animate:{x:0},exit:{x:"100%"},transition:{type:"tween",duration:.25},style:{paddingTop:"env(safe-area-inset-top)"},children:o.jsx(Me,{projectName:u.name,cliTool:u.cliTool??"claude",folderPath:u.folderPath,contextData:s,onClose:d})},"panel")})]})}export{Te as MobilePage};
|
|
14
|
+
*/function he({onSelectProject:e}){const h=t(),p=s(e=>e.clearToken),{projects:f,fetchProjects:g,hasFetched:b,loading:j}=a(),v=n.useCallback(()=>{a.getState().setProjects([]),p(),h("/login")},[p,h]),[y,N]=n.useState(new Map),[w,k]=n.useState(new Set),[C,S]=n.useState(!1);n.useEffect(()=>{g()},[g]);const I=n.useCallback(e=>{e.status&&N(t=>{const s=new Map(t);return s.set(e.projectId,e.status),s}),void 0!==e.active&&k(t=>{const s=new Set(t);return e.active?s.add(e.projectId):s.delete(e.projectId),s})},[]);r({onActivityUpdate:I});const{applyOrder:P}=l(),z=P(f.filter(e=>!e.archived));return o.jsxs("div",{className:"flex flex-col h-full",children:[o.jsxs("div",{className:"flex items-center gap-3 px-4 h-12 border-b border-border shrink-0",children:[o.jsx("span",{className:"font-semibold text-base flex-1",children:"CC Web"}),o.jsx(c,{}),o.jsx("button",{onClick:()=>{(async()=>{S(!0);try{await g()}finally{S(!1)}})()},className:"text-muted-foreground active:text-foreground",disabled:C,"aria-label":"Refresh",children:o.jsx(i,{className:d("h-4 w-4",C&&"animate-spin")})}),o.jsx("button",{onClick:()=>h("/settings"),className:"text-muted-foreground active:text-foreground","aria-label":"Settings",children:o.jsx(u,{className:"h-4 w-4"})}),o.jsx("button",{onClick:v,className:"text-muted-foreground active:text-foreground","aria-label":"Logout",children:o.jsx(x,{className:"h-4 w-4"})}),!me&&o.jsx("button",{onClick:()=>h("/"),className:"text-muted-foreground active:text-foreground","aria-label":"Desktop mode",children:o.jsx(m,{className:"h-4 w-4"})})]}),o.jsxs("div",{className:"flex-1 overflow-y-auto px-3 py-3",children:[j&&!b&&o.jsx("div",{className:"text-center text-muted-foreground text-sm py-12",children:"加载中..."}),b&&0===z.length&&o.jsx("div",{className:"text-center text-muted-foreground text-sm py-12",children:"暂无项目"}),o.jsx("div",{className:"grid grid-cols-2 gap-2",children:z.map(t=>{var s;const a="running"===(s=t,y.get(s.id)??s.status??"stopped"),n=w.has(t.id),r=o.jsxs("button",{onClick:()=>e(t.id),className:d("w-full text-left rounded-xl border bg-card p-2.5 active:bg-accent transition-colors",n?"border-transparent":"border-border"),children:[o.jsxs("div",{className:"flex items-center gap-1.5 mb-1",children:[o.jsx("span",{className:d("w-2 h-2 rounded-full shrink-0",a?"bg-green-500":"bg-zinc-400")}),o.jsx("span",{className:"font-medium text-sm truncate flex-1",children:t.name})]}),o.jsx("div",{className:"text-[10px] text-muted-foreground font-mono truncate",children:t.cliTool??"claude"})]});return o.jsx("div",{className:n?"card-active-glow rounded-xl":void 0,children:r},t.id)})})]})]})}function pe(e){if(!e.phase)return null;if("thinking"===e.phase)return"思考中";if("tool_result"===e.phase)return"处理结果";if("tool_use"===e.phase){const t=(e.detail||"").toLowerCase();return"bash"===t?"执行命令":"read"===t?"读取文件":"edit"===t||"multiedit"===t?"编辑文件":"write"===t?"写入文件":"grep"===t?"搜索内容":"glob"===t?"匹配文件":"webfetch"===t||"websearch"===t?"访问网络":"task"===t?"调度子任务":"todowrite"===t?"更新任务列表":"notebookedit"===t?"编辑 Notebook":e.detail?`调用 ${e.detail}`:"调用工具"}return null}function fe({project:e,onBack:t,onOpenPanel:s,onContextUpdate:a}){const[r,l]=n.useState(""),c=n.useRef(null),i=n.useRef(null),[u,x]=n.useState([]),m=n.useCallback(e=>{x(t=>{const s=[...t,e];return s.length>200?s.slice(-200):s})},[]),P=n.useRef(null),z=n.useCallback(e=>{var t;"stopped"===e&&(null==(t=P.current)||t.call(P,"stopped"))},[]),[M,U]=n.useState(null);n.useEffect(()=>{const t=t=>{const s=t.detail;s&&s.projectId===e.id&&("cli_prompt_detected"===s.type?U({kind:s.kind,label:s.label,detectedAt:s.detectedAt,options:s.options}):"cli_prompt_dismissed"===s.type&&U(e=>(null==e?void 0:e.kind)===s.kind?null:e))};return window.addEventListener("ccweb:cli-prompt-msg",t),()=>window.removeEventListener("ccweb:cli-prompt-msg",t)},[e.id]);const[T,A]=n.useState([]),E=n.useRef(new Set),D=n.useCallback(e=>{E.current.has(e.toolUseId)||A(t=>t.some(t=>t.toolUseId===e.toolUseId)?t:[...t,{projectId:e.projectId,toolUseId:e.toolUseId,toolName:e.toolName,toolInput:e.toolInput,sessionId:e.sessionId,createdAt:e.createdAt}])},[]),$=n.useCallback(e=>{E.current.add(e.toolUseId),A(t=>t.filter(t=>t.toolUseId!==e.toolUseId))},[]),L=n.useCallback(e=>{E.current.add(e),A(t=>t.filter(t=>t.toolUseId!==e))},[]),[R,_]=n.useState(null),F=n.useRef(0),H=n.useCallback(e=>{var t,s,a;if(!e.active)return void _(null);if("text"===(null==(t=e.semantic)?void 0:t.phase))return void _(null);const n=null==(s=e.semantic)?void 0:s.phase,r=null==(a=e.semantic)?void 0:a.detail;_(e=>e?e.phase===n&&e.detail===r?e:{...e,phase:n,detail:r}:{id:"mab"+ ++F.current,phase:n,detail:r})},[]),{sendInput:O,connected:Q}=h({projectId:e.id,enabled:!0,onChatMessage:m,onStatusChange:z,onContextUpdate:a,onApprovalRequest:D,onApprovalResolved:$,onSemanticUpdate:H});n.useEffect(()=>{let t=!1;if(U(null),Q)return p(e.id).then(e=>{!t&&e.active&&U({kind:e.active.kind,label:e.active.label,detectedAt:e.active.detectedAt,options:e.active.options})}).catch(()=>{}),()=>{t=!0}},[e.id,Q]),n.useEffect(()=>{if(!Q)return;if("claude"!==e.cliTool)return;let t=!1;return f(e.id).then(e=>{if(t)return;const s=e.pending.filter(e=>!E.current.has(e.toolUseId));A(e=>{const t=new Map;for(const a of s)t.set(a.toolUseId,a);for(const s of e)t.has(s.toolUseId)||E.current.has(s.toolUseId)||t.set(s.toolUseId,s);return[...t.values()]})}).catch(()=>{}),()=>{t=!0}},[e.id,e.cliTool,Q]);const{state:X,setState:Y,messages:Z,hasMoreHistory:ee,loadMoreHistory:te,sendMessage:se,isWaking:ae}=g({project:e,liveMessages:u,ws:{send:O,connected:Q},historyLimit:20});P.current=Y;const ne=n.useRef(Q);n.useEffect(()=>{!ne.current&&Q&&x([]),ne.current=Q},[Q]);const re=(()=>{for(let e=Z.length-1;e>=0;e--)if("assistant"===Z[e].role)return e;return-1})(),[le,de]=n.useState([]),[ue,me]=n.useState([]),[he,fe]=n.useState(null),[ge,be]=n.useState(null),je=n.useRef(!1);n.useEffect(()=>{b().then(de).catch(()=>{}),j(e.id).then(me).catch(()=>{})},[e.id]);const ve=n.useCallback(e=>{const t=i.current;if(!t)return void l(t=>t+e);const s=t.selectionStart??r.length,a=t.selectionEnd??r.length,n=r.slice(0,s)+e+r.slice(a);l(n),requestAnimationFrame(()=>{t.focus();const a=s+e.length;t.setSelectionRange(a,a),t.style.height="auto",t.style.height=Math.min(t.scrollHeight,128)+"px"})},[r]),ye=n.useCallback(e=>{fe(null),ve(e+" ")},[ve]),Ne=n.useCallback(t=>{const s=e.folderPath;let a=t;s&&(t===s||t.startsWith(s+"/")||t.startsWith(s+"\\"))&&(a=t.slice(s.length).replace(/^[/\\]+/,"")),fe(null),ve(`@${a} `)},[e.folderPath,ve]),we=n.useCallback(async()=>{if("skills"!==he){if(!je.current){je.current=!0;try{const t=await v(e.cliTool??"claude",e.id);be(t)}catch{be({builtin:[],custom:[],plugins:[],mcp:[]})}finally{je.current=!1}}fe("skills")}else fe(null)},[he,e.cliTool,e.id]),ke=n.useCallback(async()=>{const e=c.current,t=(null==e?void 0:e.scrollHeight)??0;await te(),requestAnimationFrame(()=>{e&&(e.scrollTop+=e.scrollHeight-t)})},[te]),Ce=n.useRef(0);n.useEffect(()=>{const e=c.current;if(!e)return;const t=Z.length>Ce.current,s=0===Ce.current&&Z.length>0;Ce.current=Z.length,s?e.scrollTo({top:e.scrollHeight}):t&&e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},[Z,T.length]);const[Se,Ie]=n.useState(!1),Pe=n.useCallback(async()=>{const e=r.trim();if(!e||Se)return;Ie(!0);const t=await se(e);Ie(!1),"delivered"===t&&(l(""),i.current&&(i.current.style.height="auto"))},[r,Se,se]),ze=y(Pe,"shift"),Me=n.useCallback(async(t,s)=>{fe(null);try{"failed"===await se(t.command)?N.error("快捷命令未送达,请重试或检查会话"):"project"===s&&w(e.id,t.id,!0).catch(e=>{console.error("Failed to mark shortcut used:",e)})}catch(a){console.error("Shortcut send error:",a),N.error("快捷命令发送失败")}},[se,e.id]),Ue="live"===X;return o.jsxs("div",{className:"flex flex-col h-full bg-background",children:[o.jsxs("div",{className:"flex items-center gap-2 px-3 h-12 border-b border-border shrink-0",children:[o.jsx("button",{onClick:t,className:"text-muted-foreground active:text-foreground p-1",children:o.jsx(k,{className:"h-5 w-5"})}),o.jsxs("div",{className:"flex items-center gap-1.5 flex-1 min-w-0",children:[o.jsx("span",{className:"font-medium text-sm truncate",children:e.name}),o.jsx("span",{className:d("w-2 h-2 rounded-full shrink-0",Ue?"bg-green-500":ae?"bg-yellow-400 animate-pulse":"bg-zinc-400")})]}),o.jsx("button",{onClick:s,className:"text-muted-foreground active:text-foreground p-1",children:o.jsx(xe,{className:"h-5 w-5"})})]}),o.jsxs("div",{ref:c,className:"flex-1 overflow-y-auto px-3 py-3 space-y-3 min-h-0",children:[ee&&o.jsx("div",{className:"flex justify-center pb-1",children:o.jsxs("button",{onClick:()=>{ke()},className:"flex items-center gap-1 px-3 py-1.5 rounded-full text-xs text-muted-foreground border border-border active:bg-accent transition-colors",children:[o.jsx(oe,{className:"h-3 w-3"}),"加载更早消息"]})}),Z.map((e,t)=>{const s="user"===e.role;return o.jsx("div",{className:d("flex",s?"justify-end":"justify-start"),children:o.jsx("div",{className:d("max-w-[85%] rounded-xl px-3 py-2 break-words text-sm leading-relaxed",s?"bg-blue-500/15 text-foreground border border-blue-500/20 rounded-br-sm whitespace-pre-wrap":"bg-secondary text-secondary-foreground border border-border rounded-bl-sm"),children:s?e.content:o.jsx(q,{content:e.content,blocks:e.blocks,isLatest:t===re})})},e.id)}),T.map(e=>o.jsx(W,{approval:e,onResolved:L},e.toolUseId)),M&&o.jsx(B,{prompt:M,onSelect:async t=>{await C(e.id,t)}}),R&&0===T.length&&o.jsx("div",{className:"flex justify-start",children:o.jsxs("div",{className:"rounded-2xl rounded-bl-md px-3 py-1.5 bg-black/5 dark:bg-white/10 border border-black/10 dark:border-white/15 flex items-center gap-2 text-xs text-muted-foreground",children:[o.jsx(V,{}),pe(R)&&o.jsx("span",{children:pe(R)})]})},R.id),0===Z.length&&0===T.length&&!R&&"stopped"===X&&o.jsx("div",{className:"flex items-center justify-center h-full text-muted-foreground/40 text-sm",children:"暂无对话记录"}),ae&&o.jsx("div",{className:"flex items-center justify-center py-4 text-yellow-400 text-sm animate-pulse",children:"启动中..."})]}),"global"===he||"project"===he?o.jsx("div",{className:"border-t border-border max-h-48 overflow-y-auto shrink-0",children:o.jsxs("div",{className:"px-3 py-2 space-y-1",children:[("global"===he?le:ue).map(e=>o.jsxs("button",{onClick:()=>Me(e,he),disabled:ae,className:d("w-full text-left rounded-md px-2.5 py-2 text-sm active:bg-accent transition-colors border border-border/50",ae&&"opacity-50 cursor-not-allowed"),children:[o.jsx("div",{className:"font-medium text-xs",children:e.label}),o.jsx("div",{className:"text-[11px] text-muted-foreground font-mono truncate",children:e.command})]},e.id)),0===("global"===he?le:ue).length&&o.jsx("div",{className:"text-center text-muted-foreground text-xs py-3",children:"暂无快捷 Prompts"})]})}):"skills"===he&&ge?o.jsx("div",{className:"border-t border-border shrink-0",children:o.jsx(K,{data:ge,onCommand:ye})}):"files"===he&&e.folderPath?o.jsx("div",{className:"border-t border-border shrink-0",children:o.jsx(G,{projectPath:e.folderPath,onSelect:Ne})}):null,o.jsxs("div",{className:"flex items-center gap-1.5 px-3 py-1.5 border-t border-border shrink-0",children:[o.jsx("button",{onClick:()=>{we()},title:"斜杠命令",className:d("flex items-center justify-center w-7 h-7 rounded font-mono text-base transition-colors","skills"===he?"bg-accent text-foreground font-medium":"text-muted-foreground active:bg-accent"),children:"/"}),o.jsx("button",{onClick:()=>fe(e=>"files"===e?null:"files"),disabled:!e.folderPath,title:"引用文件",className:d("flex items-center justify-center w-7 h-7 rounded font-mono text-base transition-colors","files"===he?"bg-accent text-foreground font-medium":e.folderPath?"text-muted-foreground active:bg-accent":"text-muted-foreground/30 cursor-not-allowed"),children:"@"}),le.length>0&&o.jsxs("button",{onClick:()=>fe(e=>"global"===e?null:"global"),className:d("flex items-center gap-1 px-2 py-1 rounded-md text-xs transition-colors","global"===he?"bg-accent text-foreground font-medium":"text-muted-foreground active:bg-accent"),children:[o.jsx(J,{className:"h-3 w-3"}),"全局","global"===he&&o.jsx(ce,{className:"h-3 w-3"})]}),ue.length>0&&o.jsxs("button",{onClick:()=>fe(e=>"project"===e?null:"project"),className:d("flex items-center gap-1 px-2 py-1 rounded-md text-xs transition-colors","project"===he?"bg-accent text-foreground font-medium":"text-muted-foreground active:bg-accent"),children:[o.jsx(ie,{className:"h-3 w-3"}),"项目","project"===he&&o.jsx(ce,{className:"h-3 w-3"})]})]}),o.jsx("div",{className:"border-t border-border px-3 py-2 shrink-0",style:{paddingBottom:"max(0.5rem, env(safe-area-inset-bottom))"},children:o.jsxs("div",{className:"flex items-end gap-2",children:[o.jsx("textarea",{ref:i,value:r,onChange:e=>l(e.target.value),onKeyDown:ze,disabled:ae||Se,placeholder:ae?"启动中...":Se?"发送中…":"stopped"===X?"输入消息(自动启动)...":"输入消息...",rows:1,className:d("flex-1 resize-none rounded-md border border-input bg-transparent px-3 py-2 text-sm outline-none","focus:ring-1 focus:ring-ring placeholder:text-muted-foreground/50","max-h-32 overflow-y-auto",(ae||Se)&&"opacity-50 cursor-not-allowed"),style:{minHeight:"2.5rem"},onInput:e=>{const t=e.currentTarget;t.style.height="auto",t.style.height=Math.min(t.scrollHeight,128)+"px"}}),o.jsx("button",{onClick:Pe,disabled:ae||Se||!r.trim(),className:d("shrink-0 p-2 rounded-md transition-colors",r.trim()&&!Se?"text-blue-500 active:bg-blue-500/10":"text-muted-foreground/30"),children:Se?o.jsx(S,{className:"h-5 w-5 animate-spin"}):o.jsx(I,{className:"h-5 w-5"})})]})})]})}const ge=A.lazy(()=>E(()=>import("./OfficePreview-DY-ew_ex.js"),__vite__mapDeps([0,1,2,3])).then(e=>({default:e.OfficePreview}))),be=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","ico","avif"]),je=new Set(["docx","xlsx","xls","pptx"]),ve={js:"javascript",jsx:"jsx",ts:"typescript",tsx:"tsx",py:"python",rb:"ruby",go:"go",rs:"rust",java:"java",kt:"kotlin",swift:"swift",c:"c",cpp:"cpp",h:"c",cs:"csharp",php:"php",sh:"bash",bash:"bash",zsh:"bash",yaml:"yaml",yml:"yaml",json:"json",toml:"toml",html:"html",htm:"html",xml:"xml",svg:"xml",css:"css",scss:"scss",less:"less",sql:"sql",graphql:"graphql",gql:"graphql",dockerfile:"docker",makefile:"makefile",r:"r",lua:"lua",dart:"dart",zig:"zig"};function ye(e){return e.split("/").pop()??e}function Ne({filePath:e,onBack:t}){const[s,a]=n.useState(null),[r,l]=n.useState(!0),[c,i]=n.useState(null),{resolved:d}=P(),u=function(e){const t=e.split("/").pop()??"",s=t.toLowerCase();if("dockerfile"===s)return"dockerfile";if("makefile"===s)return"makefile";const a=t.lastIndexOf(".");return a>=0?t.slice(a+1).toLowerCase():""}(e),x=be.has(u),m=je.has(u),h=ve[u],p="dark"===d;n.useEffect(()=>{x||m?l(!1):(l(!0),i(null),z(e).then(a).catch(e=>i(e instanceof Error?e.message:"Failed to load")).finally(()=>l(!1)))},[e,x,m]);const f=T(e),g=n.useMemo(()=>{const e=M();return e?`${f}&token=${encodeURIComponent(e)}`:f},[f]),b=n.useMemo(()=>x?`${g}&t=${Date.now()}`:"",[g,x]);return o.jsxs("div",{className:"flex flex-col h-full",children:[o.jsxs("div",{className:"flex items-center gap-2 px-3 h-12 border-b border-border shrink-0",children:[o.jsx("button",{onClick:t,className:"text-muted-foreground active:text-foreground p-1",children:o.jsx(k,{className:"h-5 w-5"})}),o.jsx("span",{className:"flex-1 text-sm font-medium truncate",children:ye(e)}),o.jsx("a",{href:g,download:!0,className:"text-muted-foreground active:text-foreground p-1",onClick:e=>e.stopPropagation(),children:o.jsx(U,{className:"h-4 w-4"})})]}),o.jsxs("div",{className:"flex-1 overflow-auto min-h-0",children:[r&&o.jsx("div",{className:"flex items-center justify-center py-12",children:o.jsx(S,{className:"h-5 w-5 animate-spin text-muted-foreground"})}),c&&o.jsx("div",{className:"text-center text-destructive text-sm py-12 px-4",children:c}),x&&o.jsx("div",{className:"flex items-center justify-center p-4 h-full",children:o.jsx("img",{src:b,alt:ye(e),className:"max-w-full max-h-full object-contain rounded",style:{touchAction:"pinch-zoom"}})}),m&&o.jsx(n.Suspense,{fallback:o.jsx("div",{className:"flex items-center justify-center py-12",children:o.jsx(S,{className:"h-5 w-5 animate-spin text-muted-foreground"})}),children:o.jsx(ge,{filePath:e,ext:u,zoom:100})}),s&&(s.binary||s.tooLarge)&&o.jsxs("div",{className:"text-center py-12 px-4 space-y-3",children:[o.jsxs("p",{className:"text-muted-foreground text-sm",children:[s.binary?"二进制文件":"文件过大",s.size>0&&` (${j=s.size,j<1024?`${j} B`:j<1048576?`${(j/1024).toFixed(1)} KB`:`${(j/1048576).toFixed(1)} MB`})`]}),o.jsxs("a",{href:g,download:!0,className:"inline-flex items-center gap-1.5 text-sm text-blue-500 active:text-blue-400",children:[o.jsx(U,{className:"h-4 w-4"}),"下载文件"]})]}),s&&!s.binary&&!s.tooLarge&&null!=s.content&&o.jsxs(o.Fragment,{children:["md"===u&&o.jsx("div",{className:"prose prose-sm dark:prose-invert max-w-none px-4 py-3",children:o.jsx(Q,{remarkPlugins:[Y,Z],rehypePlugins:[X],urlTransform:(e,t,s)=>"src"===t&&"img"===s.tagName?e:te(e),components:{img:({src:t,alt:s,...a})=>o.jsx("img",{...a,src:ee(e,t,M()),alt:s??"",loading:"lazy",style:{maxWidth:"100%",height:"auto"}})},children:s.content})}),"md"!==u&&h&&o.jsx(se,{language:h,style:p?ae:ne,customStyle:{margin:0,fontSize:"12px",borderRadius:0},showLineNumbers:!0,children:s.content}),"md"!==u&&!h&&o.jsx("pre",{className:"p-4 text-xs font-mono whitespace-pre-wrap break-words",children:s.content})]})]})]});var j}const we=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","ico","avif"]),ke=new Set(["js","jsx","ts","tsx","py","rb","go","rs","java","c","cpp","h","swift","kt","cs","php","sh","bash","zsh","r","lua","dart","zig","css","scss","less","html","htm","xml","sql"]),Ce=new Set(["json","yaml","yml","toml","csv","tsv"]);function Se({entry:e}){if("dir"===e.type)return o.jsx(L,{className:"h-8 w-8 text-blue-400"});const t=function(e){const t=e.lastIndexOf(".");return t>=0?e.slice(t+1).toLowerCase():""}(e.name);return we.has(t)?o.jsx(re,{className:"h-8 w-8 text-emerald-400"}):ke.has(t)?o.jsx(de,{className:"h-8 w-8 text-orange-400"}):Ce.has(t)?o.jsx(ue,{className:"h-8 w-8 text-yellow-400"}):"md"===t?o.jsx(le,{className:"h-8 w-8 text-sky-400"}):o.jsx(R,{className:"h-8 w-8 text-muted-foreground"})}function Ie({rootPath:e,onClose:t}){const[s,a]=n.useState(e),[r,l]=n.useState([]),[c,i]=n.useState(!0),[d,u]=n.useState(null),x=n.useCallback(async e=>{i(!0);try{const t=[...(await D(e)).entries].sort((e,t)=>e.type!==t.type?"dir"===e.type?-1:1:e.name.localeCompare(t.name));l(t),a(e)}catch{l([])}finally{i(!1)}},[]);n.useEffect(()=>{x(e)},[e,x]);const m=s!==e,h=s.startsWith(e)?s.slice(e.length)||"/":s;return d?o.jsx(Ne,{filePath:d,onBack:()=>u(null)}):o.jsxs("div",{className:"flex flex-col h-full",children:[o.jsxs("div",{className:"flex items-center gap-2 px-3 h-12 border-b border-border shrink-0",children:[o.jsx("button",{onClick:t,className:"text-muted-foreground active:text-foreground p-1",children:o.jsx($,{className:"h-5 w-5"})}),o.jsxs("div",{className:"flex items-center gap-1 flex-1 min-w-0 text-sm",children:[m&&o.jsx("button",{onClick:()=>{if(s===e)return;const t=s.replace(/\/[^/]+$/,"")||"/";t.startsWith(e)&&x(t)},className:"text-muted-foreground active:text-foreground p-0.5 shrink-0",children:o.jsx(k,{className:"h-4 w-4"})}),o.jsx("span",{className:"truncate text-muted-foreground font-mono text-xs",children:h})]})]}),o.jsxs("div",{className:"flex-1 overflow-y-auto px-3 py-3",children:[c&&o.jsx("div",{className:"flex items-center justify-center py-12",children:o.jsx(S,{className:"h-5 w-5 animate-spin text-muted-foreground"})}),!c&&0===r.length&&o.jsx("div",{className:"text-center text-muted-foreground text-sm py-12",children:"空目录"}),!c&&o.jsx("div",{className:"grid grid-cols-3 gap-1",children:r.map(e=>o.jsxs("button",{onClick:()=>(e=>{"dir"===e.type?x(e.path):u(e.path)})(e),className:"flex flex-col items-center gap-1 p-2 rounded-md active:bg-accent transition-colors",children:[o.jsx(Se,{entry:e}),o.jsx("span",{className:"text-[11px] text-center leading-tight w-full line-clamp-2 break-all",children:e.name})]},e.path))})]})]})}function Pe(e){return e<50?"text-green-400":e<80?"text-yellow-400":"text-red-400"}function ze(e){return e<50?"bg-green-500":e<80?"bg-yellow-500":"bg-red-500"}function Me({projectName:e,cliTool:t,folderPath:s,contextData:a,onClose:r}){const[l,c]=n.useState(new Set(["context","usage","files"])),[u,x]=n.useState(null),[m,h]=n.useState(!1),p=e=>{c(t=>{const s=new Set(t);return s.has(e)?s.delete(e):s.add(e),s})};n.useEffect(()=>{h(!0),_(t).then(x).catch(()=>x(null)).finally(()=>h(!1))},[t]);const f=a?Math.round(a.usedPercentage):null;return o.jsxs("div",{className:"flex flex-col h-full",children:[o.jsxs("div",{className:"flex items-center gap-2 px-3 h-12 border-b border-border shrink-0",children:[o.jsx("button",{onClick:r,className:"text-muted-foreground active:text-foreground p-1",children:o.jsx($,{className:"h-5 w-5"})}),o.jsx("span",{className:"flex-1 font-medium text-sm truncate",children:e})]}),o.jsxs("div",{className:"flex-1 overflow-y-auto",children:[o.jsxs("button",{onClick:()=>p("context"),className:"w-full flex items-center gap-2 px-4 py-2.5 border-b border-border/50 active:bg-accent",children:[l.has("context")?o.jsx(ce,{className:"h-3.5 w-3.5 text-muted-foreground"}):o.jsx(F,{className:"h-3.5 w-3.5 text-muted-foreground"}),o.jsx("span",{className:"text-sm font-medium",children:"上下文"}),null!==f&&o.jsxs("span",{className:d("text-xs font-mono ml-auto",Pe(f)),children:[f,"%"]})]}),l.has("context")&&o.jsx("div",{className:"px-4 py-3 border-b border-border/50",children:null!==f&&a?o.jsxs("div",{className:"space-y-2",children:[o.jsxs("div",{className:"flex items-center gap-2",children:[o.jsx("div",{className:"flex-1 h-2 bg-secondary rounded-full overflow-hidden",children:o.jsx("div",{className:d("h-full rounded-full transition-all",ze(f)),style:{width:`${Math.min(f,100)}%`}})}),o.jsxs("span",{className:d("text-xs font-mono w-10 text-right",Pe(f)),children:[f,"%"]})]}),o.jsxs("div",{className:"grid grid-cols-2 gap-x-4 gap-y-1 text-[11px] text-muted-foreground",children:[o.jsx("span",{children:"窗口大小"}),o.jsx("span",{className:"text-right font-mono",children:a.contextWindowSize>=1e6?`${(a.contextWindowSize/1e6).toFixed(1)}M`:`${Math.round(a.contextWindowSize/1e3)}K`}),o.jsx("span",{children:"输入 tokens"}),o.jsx("span",{className:"text-right font-mono",children:a.inputTokens.toLocaleString()}),o.jsx("span",{children:"输出 tokens"}),o.jsx("span",{className:"text-right font-mono",children:a.outputTokens.toLocaleString()})]})]}):o.jsx("div",{className:"text-xs text-muted-foreground/50 text-center py-2",children:"暂无数据"})}),o.jsxs("div",{className:"w-full flex items-center gap-2 px-4 py-2.5 border-b border-border/50 cursor-pointer",role:"button",tabIndex:0,onClick:()=>p("usage"),onKeyDown:e=>{"Enter"!==e.key&&" "!==e.key||p("usage")},children:[l.has("usage")?o.jsx(ce,{className:"h-3.5 w-3.5 text-muted-foreground"}):o.jsx(F,{className:"h-3.5 w-3.5 text-muted-foreground"}),o.jsx("span",{className:"text-sm font-medium",children:"用量"}),o.jsx("button",{onClick:e=>{e.stopPropagation(),(async()=>{h(!0);try{const{refreshUsage:e}=await E(async()=>{const{refreshUsage:e}=await import("./index-nYsy3LMF.js").then(e=>e.bU);return{refreshUsage:e}},__vite__mapDeps([1,2]));x(await e(t))}catch{}finally{h(!1)}})()},className:"ml-auto text-muted-foreground active:text-foreground",children:o.jsx(i,{className:d("h-3 w-3",m&&"animate-spin")})})]}),l.has("usage")&&o.jsx("div",{className:"px-4 py-3 border-b border-border/50",children:u?o.jsxs("div",{className:"space-y-2",children:[u.planName&&o.jsxs("div",{className:"text-[11px] text-muted-foreground",children:["Plan: ",o.jsx("span",{className:"font-medium text-foreground",children:u.planName})]}),o.jsx(Ue,{label:"5h",bucket:u.fiveHour}),o.jsx(Ue,{label:"7d",bucket:u.sevenDay}),u.sevenDaySonnet&&o.jsx(Ue,{label:"7d Sonnet",bucket:u.sevenDaySonnet}),u.sevenDayOpus&&o.jsx(Ue,{label:"7d Opus",bucket:u.sevenDayOpus}),!u.fiveHour&&!u.sevenDay&&o.jsx("div",{className:"text-xs text-muted-foreground/50 text-center",children:"暂无数据"})]}):o.jsx("div",{className:"text-xs text-muted-foreground/50 text-center py-2",children:m?"加载中...":"暂无数据"})}),o.jsxs("button",{onClick:()=>p("files"),className:"w-full flex items-center gap-2 px-4 py-2.5 border-b border-border/50 active:bg-accent",children:[l.has("files")?o.jsx(ce,{className:"h-3.5 w-3.5 text-muted-foreground"}):o.jsx(F,{className:"h-3.5 w-3.5 text-muted-foreground"}),o.jsx("span",{className:"text-sm font-medium",children:"文件"})]}),l.has("files")&&o.jsx("div",{className:"h-[60vh]",children:o.jsx(Ie,{rootPath:s,onClose:()=>p("files")})})]})]})}function Ue({label:e,bucket:t}){if(!t||void 0===t.utilization)return null;const s=t.utilization,a=function(e){if(!e)return"";const t=new Date(e).getTime()-Date.now();if(t<=0)return"即将重置";const s=Math.floor(t/36e5),a=Math.floor(t%36e5/6e4);return s>0?`${s}h${a}m`:`${a}m`}(t.resetAt);return o.jsxs("div",{className:"flex items-center gap-2",children:[o.jsx("span",{className:"text-xs text-muted-foreground w-16",children:e}),o.jsx("div",{className:"flex-1 h-1.5 bg-secondary rounded-full overflow-hidden",children:o.jsx("div",{className:d("h-full rounded-full",ze(s)),style:{width:`${Math.min(s,100)}%`}})}),o.jsxs("span",{className:d("text-xs font-mono w-8 text-right",Pe(s)),children:[s,"%"]}),a&&o.jsx("span",{className:"text-[10px] text-muted-foreground/60",children:a})]})}function Te(){n.useEffect(()=>{const e=document.querySelector('meta[name="viewport"]');if(!e)return;const t=e.getAttribute("content")??"";return e.setAttribute("content","width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"),()=>{e.setAttribute("content",t)}},[]);const[e,t]=n.useState({screen:"list"}),[s,r]=n.useState(null),l=a(e=>e.projects),c=n.useCallback(e=>{t({screen:"chat",projectId:e}),r(null)},[]),i=n.useCallback(e=>{t({screen:"panel",projectId:e})},[]),d=n.useCallback(()=>{t(e=>"panel"===e.screen?{screen:"chat",projectId:e.projectId}:{screen:"list"})},[]),u="list"!==e.screen?l.find(t=>t.id===e.projectId):void 0;return o.jsxs("div",{className:"fixed inset-0 bg-background overflow-hidden",children:[o.jsxs(H,{mode:"wait",children:["list"===e.screen&&o.jsx(O.div,{className:"absolute inset-0",initial:{opacity:0},animate:{opacity:1},exit:{x:"-30%",opacity:0},transition:{duration:.2},style:{paddingTop:"env(safe-area-inset-top)"},children:o.jsx(he,{onSelectProject:c})},"list"),"chat"===e.screen&&u&&o.jsx(O.div,{className:"absolute inset-0",initial:{x:"100%"},animate:{x:0},exit:{x:"100%"},transition:{type:"tween",duration:.25},style:{paddingTop:"env(safe-area-inset-top)"},children:o.jsx(fe,{project:u,onBack:d,onOpenPanel:()=>i(e.projectId),onContextUpdate:r})},`chat-${e.projectId}`)]}),o.jsx(H,{children:"panel"===e.screen&&u&&o.jsx(O.div,{className:"absolute inset-0 z-50 bg-background",initial:{x:"100%"},animate:{x:0},exit:{x:"100%"},transition:{type:"tween",duration:.25},style:{paddingTop:"env(safe-area-inset-top)"},children:o.jsx(Me,{projectName:u.name,cliTool:u.cliTool??"claude",folderPath:u.folderPath,contextData:s,onClose:d})},"panel")})]})}export{Te as MobilePage};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-
|
|
2
|
-
import{j as e,r as t,_ as s,g as r,h as a}from"./index-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-CZOz50el.js","assets/index-nYsy3LMF.js","assets/index-B55CtERr.css","assets/jszip.min-9o6zKk8v.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{j as e,r as t,_ as s,g as r,h as a}from"./index-nYsy3LMF.js";import{p as n}from"./purify.es-CgRAQgUo.js";async function l(e){let t=a(e);const s=r();s&&(t+=`${t.includes("?")?"&":"?"}token=${encodeURIComponent(s)}`);const n=await fetch(t);if(!n.ok)throw new Error(`Failed to fetch file: ${n.status}`);return n.arrayBuffer()}function o({filePath:r,zoom:a}){const[o,i]=t.useState(""),[d,c]=t.useState(null),[x,u]=t.useState(!0);return t.useEffect(()=>{let e=!1;return u(!0),c(null),(async()=>{try{const t=await s(()=>import("./index-CZOz50el.js").then(e=>e.i),__vite__mapDeps([0,1,2,3])),a=await l(r),n=await t.convertToHtml({arrayBuffer:a});e||i(n.value)}catch(t){e||c(t instanceof Error?t.message:"Failed to render docx")}finally{e||u(!1)}})(),()=>{e=!0}},[r]),x?e.jsx("p",{className:"text-sm text-muted-foreground p-4",children:"加载 Word 文档中..."}):d?e.jsx("p",{className:"text-sm text-destructive p-4",children:d}):e.jsx("div",{className:"p-6 prose dark:prose-invert max-w-none",style:{fontSize:12*a/100+"px"},dangerouslySetInnerHTML:{__html:n.sanitize(o)}})}function i({filePath:r,zoom:a}){var o;const[i,d]=t.useState([]),[c,x]=t.useState(0),[u,p]=t.useState(null),[m,f]=t.useState(!0);return t.useEffect(()=>{let e=!1;return f(!0),p(null),(async()=>{try{const t=await s(()=>import("./xlsx-DfDjAMCE.js"),[]),a=await l(r),n=t.read(a,{type:"array"}),o=n.SheetNames.map(e=>({name:e,html:t.utils.sheet_to_html(n.Sheets[e],{editable:!1})}));e||(d(o),x(0))}catch(t){e||p(t instanceof Error?t.message:"Failed to render xlsx")}finally{e||f(!1)}})(),()=>{e=!0}},[r]),m?e.jsx("p",{className:"text-sm text-muted-foreground p-4",children:"加载 Excel 文件中..."}):u?e.jsx("p",{className:"text-sm text-destructive p-4",children:u}):0===i.length?e.jsx("p",{className:"text-sm text-muted-foreground p-4",children:"空文件"}):e.jsxs("div",{className:"flex flex-col h-full",children:[i.length>1&&e.jsx("div",{className:"flex gap-0.5 px-3 py-1.5 border-b border-border bg-muted/30 flex-shrink-0 overflow-x-auto",children:i.map((t,s)=>e.jsx("button",{onClick:()=>x(s),className:"px-3 py-1 text-xs rounded-t transition-colors whitespace-nowrap "+(s===c?"bg-background text-foreground border border-b-0 border-border":"text-muted-foreground hover:text-foreground"),children:t.name},s))}),e.jsx("div",{className:"flex-1 overflow-auto p-2 xlsx-preview",style:{fontSize:12*a/100+"px"},dangerouslySetInnerHTML:{__html:n.sanitize((null==(o=i[c])?void 0:o.html)??"")}}),e.jsx("style",{children:"\n .xlsx-preview table { border-collapse: collapse; width: auto; min-width: 100%; }\n .xlsx-preview td, .xlsx-preview th {\n border: 1px solid hsl(var(--border));\n padding: 4px 8px;\n text-align: left;\n white-space: nowrap;\n font-size: inherit;\n }\n .xlsx-preview th { background: hsl(var(--muted)); font-weight: 600; }\n .xlsx-preview tr:hover td { background: hsl(var(--accent) / 0.3); }\n "})]})}function d({filePath:r,zoom:a}){const[n,o]=t.useState([]),[i,d]=t.useState(null),[c,x]=t.useState(!0);return t.useEffect(()=>{let e=!1;return x(!0),d(null),(async()=>{try{const t=await l(r),a=await async function(e){const{default:t}=await s(async()=>{const{default:e}=await import("./jszip.min-9o6zKk8v.js").then(e=>e.j);return{default:e}},__vite__mapDeps([3,1,2])),r=await t.loadAsync(e),a=[],n=Object.keys(r.files).filter(e=>/^ppt\/slides\/slide\d+\.xml$/i.test(e)).sort((e,t)=>{var s,r;return parseInt((null==(s=e.match(/slide(\d+)/))?void 0:s[1])??"0")-parseInt((null==(r=t.match(/slide(\d+)/))?void 0:r[1])??"0")});for(let s=0;s<n.length;s++){const e=await r.file(n[s]).async("text"),t=[],l=/<a:t[^>]*>([\s\S]*?)<\/a:t>/g;let o;for(;null!==(o=l.exec(e));){const e=o[1].replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').trim();e&&t.push(e)}a.push({index:s+1,texts:t})}return a}(t);e||o(a)}catch(t){e||d(t instanceof Error?t.message:"Failed to render pptx")}finally{e||x(!1)}})(),()=>{e=!0}},[r]),c?e.jsx("p",{className:"text-sm text-muted-foreground p-4",children:"加载 PPT 文件中..."}):i?e.jsx("p",{className:"text-sm text-destructive p-4",children:i}):0===n.length?e.jsx("p",{className:"text-sm text-muted-foreground p-4",children:"空文件"}):e.jsx("div",{className:"p-4 space-y-4",style:{fontSize:12*a/100+"px"},children:n.map(t=>e.jsxs("div",{className:"border border-border rounded-xl p-5 bg-muted/20",children:[e.jsxs("div",{className:"text-xs text-muted-foreground mb-2 font-medium",children:["Slide ",t.index]}),t.texts.length>0?e.jsx("div",{className:"space-y-1.5",children:t.texts.map((t,s)=>e.jsx("p",{className:"text-foreground leading-relaxed",style:{fontSize:"inherit"},children:t},s))}):e.jsx("p",{className:"text-muted-foreground text-sm italic",children:"(无文本内容)"})]},t.index))})}const c=new Set(["docx","xlsx","xls","pptx"]);function x({filePath:t,ext:s,zoom:r}){return"docx"===s?e.jsx(o,{filePath:t,zoom:r}):"xlsx"===s||"xls"===s?e.jsx(i,{filePath:t,zoom:r}):"pptx"===s?e.jsx(d,{filePath:t,zoom:r}):null}export{c as OFFICE_EXTS,x as OfficePreview};
|