@keyou007/agent-bot 0.1.17 → 0.1.18-alpha.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/CHANGELOG.md +5 -0
- package/dist/local-files/LocalFileViewerServer.js +107 -5
- package/dist/local-files/LocalFileViewerServer.js.map +1 -1
- package/dist/proxy/ProxySessionController.js +23 -3
- package/dist/proxy/ProxySessionController.js.map +1 -1
- package/npm-shrinkwrap.json +98 -2
- package/package.json +2 -1
- package/src/local-files/LocalFileViewerServer.ts +112 -5
- package/src/proxy/ProxySessionController.ts +25 -2
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keyou007/agent-bot",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18-alpha.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@keyou007/agent-bot",
|
|
9
|
-
"version": "0.1.
|
|
9
|
+
"version": "0.1.18-alpha.0",
|
|
10
10
|
"license": "GPL-3.0-only",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@agentclientprotocol/sdk": "1.2.1",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"better-sqlite3": "12.11.1",
|
|
17
17
|
"dotenv": "17.4.2",
|
|
18
18
|
"highlight.js": "11.12.0",
|
|
19
|
+
"markdown-it": "15.0.1",
|
|
19
20
|
"pino": "10.3.1",
|
|
20
21
|
"yaml": "2.9.0",
|
|
21
22
|
"zod": "4.4.3"
|
|
@@ -1927,6 +1928,22 @@
|
|
|
1927
1928
|
"url": "https://github.com/sponsors/epoberezkin"
|
|
1928
1929
|
}
|
|
1929
1930
|
},
|
|
1931
|
+
"node_modules/argparse": {
|
|
1932
|
+
"version": "3.0.1",
|
|
1933
|
+
"resolved": "https://registry.npmjs.org/argparse/-/argparse-3.0.1.tgz",
|
|
1934
|
+
"integrity": "sha512-nM4mHF/KM1v59ZNKX7zfusQz5wUAxR511YG8Vo6TyiV4aqhu++rbJW4v04xsWhpSsHFj66flT8P7znVpyO20xQ==",
|
|
1935
|
+
"funding": [
|
|
1936
|
+
{
|
|
1937
|
+
"type": "github",
|
|
1938
|
+
"url": "https://github.com/sponsors/puzrin"
|
|
1939
|
+
},
|
|
1940
|
+
{
|
|
1941
|
+
"type": "github",
|
|
1942
|
+
"url": "https://github.com/sponsors/nodeca"
|
|
1943
|
+
}
|
|
1944
|
+
],
|
|
1945
|
+
"license": "PSF-2.0"
|
|
1946
|
+
},
|
|
1930
1947
|
"node_modules/assertion-error": {
|
|
1931
1948
|
"version": "2.0.1",
|
|
1932
1949
|
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
|
|
@@ -2245,6 +2262,18 @@
|
|
|
2245
2262
|
"once": "^1.4.0"
|
|
2246
2263
|
}
|
|
2247
2264
|
},
|
|
2265
|
+
"node_modules/entities": {
|
|
2266
|
+
"version": "8.0.0",
|
|
2267
|
+
"resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz",
|
|
2268
|
+
"integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==",
|
|
2269
|
+
"license": "BSD-2-Clause",
|
|
2270
|
+
"engines": {
|
|
2271
|
+
"node": ">=20.19.0"
|
|
2272
|
+
},
|
|
2273
|
+
"funding": {
|
|
2274
|
+
"url": "https://github.com/fb55/entities?sponsor=1"
|
|
2275
|
+
}
|
|
2276
|
+
},
|
|
2248
2277
|
"node_modules/es-define-property": {
|
|
2249
2278
|
"version": "1.0.1",
|
|
2250
2279
|
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
|
@@ -3251,6 +3280,25 @@
|
|
|
3251
3280
|
"url": "https://opencollective.com/parcel"
|
|
3252
3281
|
}
|
|
3253
3282
|
},
|
|
3283
|
+
"node_modules/linkify-it": {
|
|
3284
|
+
"version": "6.1.0",
|
|
3285
|
+
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-6.1.0.tgz",
|
|
3286
|
+
"integrity": "sha512-wJ/TwpSDTLepCrQoYWYIExIKg5Zchex2Nn5yk2mFnB+6PtdkHtyLx742md9csRjjOnGkKIS/RrbY7l8D6gT9Vw==",
|
|
3287
|
+
"funding": [
|
|
3288
|
+
{
|
|
3289
|
+
"type": "github",
|
|
3290
|
+
"url": "https://github.com/sponsors/puzrin"
|
|
3291
|
+
},
|
|
3292
|
+
{
|
|
3293
|
+
"type": "github",
|
|
3294
|
+
"url": "https://github.com/sponsors/markdown-it"
|
|
3295
|
+
}
|
|
3296
|
+
],
|
|
3297
|
+
"license": "MIT",
|
|
3298
|
+
"dependencies": {
|
|
3299
|
+
"uc.micro": "^3.0.0"
|
|
3300
|
+
}
|
|
3301
|
+
},
|
|
3254
3302
|
"node_modules/locate-path": {
|
|
3255
3303
|
"version": "6.0.0",
|
|
3256
3304
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
|
@@ -3301,6 +3349,33 @@
|
|
|
3301
3349
|
"@jridgewell/sourcemap-codec": "^1.5.5"
|
|
3302
3350
|
}
|
|
3303
3351
|
},
|
|
3352
|
+
"node_modules/markdown-it": {
|
|
3353
|
+
"version": "15.0.1",
|
|
3354
|
+
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-15.0.1.tgz",
|
|
3355
|
+
"integrity": "sha512-9/7gE95FNPkfUWrjJIoHZza2iLmuJlPD0UNMxPi7bxUrbCR525YZY0r+zyfes0dZI5ZZ/uNIXUJca0pJvtw41g==",
|
|
3356
|
+
"funding": [
|
|
3357
|
+
{
|
|
3358
|
+
"type": "github",
|
|
3359
|
+
"url": "https://github.com/sponsors/puzrin"
|
|
3360
|
+
},
|
|
3361
|
+
{
|
|
3362
|
+
"type": "github",
|
|
3363
|
+
"url": "https://github.com/sponsors/markdown-it"
|
|
3364
|
+
}
|
|
3365
|
+
],
|
|
3366
|
+
"license": "MIT",
|
|
3367
|
+
"dependencies": {
|
|
3368
|
+
"argparse": "^3.0.0",
|
|
3369
|
+
"entities": "^8.0.0",
|
|
3370
|
+
"linkify-it": "^6.0.0",
|
|
3371
|
+
"mdurl": "^2.1.0",
|
|
3372
|
+
"punycode.js": "^2.3.1",
|
|
3373
|
+
"uc.micro": "^3.0.0"
|
|
3374
|
+
},
|
|
3375
|
+
"bin": {
|
|
3376
|
+
"markdown-it": "bin/markdown-it.mjs"
|
|
3377
|
+
}
|
|
3378
|
+
},
|
|
3304
3379
|
"node_modules/math-intrinsics": {
|
|
3305
3380
|
"version": "1.1.0",
|
|
3306
3381
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
|
@@ -3310,6 +3385,12 @@
|
|
|
3310
3385
|
"node": ">= 0.4"
|
|
3311
3386
|
}
|
|
3312
3387
|
},
|
|
3388
|
+
"node_modules/mdurl": {
|
|
3389
|
+
"version": "2.1.0",
|
|
3390
|
+
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.1.0.tgz",
|
|
3391
|
+
"integrity": "sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg==",
|
|
3392
|
+
"license": "MIT"
|
|
3393
|
+
},
|
|
3313
3394
|
"node_modules/mime-db": {
|
|
3314
3395
|
"version": "1.52.0",
|
|
3315
3396
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
|
@@ -3752,6 +3833,15 @@
|
|
|
3752
3833
|
"node": ">=6"
|
|
3753
3834
|
}
|
|
3754
3835
|
},
|
|
3836
|
+
"node_modules/punycode.js": {
|
|
3837
|
+
"version": "2.3.1",
|
|
3838
|
+
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
|
|
3839
|
+
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
|
|
3840
|
+
"license": "MIT",
|
|
3841
|
+
"engines": {
|
|
3842
|
+
"node": ">=6"
|
|
3843
|
+
}
|
|
3844
|
+
},
|
|
3755
3845
|
"node_modules/qs": {
|
|
3756
3846
|
"version": "6.15.3",
|
|
3757
3847
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz",
|
|
@@ -4277,6 +4367,12 @@
|
|
|
4277
4367
|
"@typescript/typescript-win32-x64": "7.0.2"
|
|
4278
4368
|
}
|
|
4279
4369
|
},
|
|
4370
|
+
"node_modules/uc.micro": {
|
|
4371
|
+
"version": "3.0.0",
|
|
4372
|
+
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-3.0.0.tgz",
|
|
4373
|
+
"integrity": "sha512-U3PppEkleoTnIfi8BozMx3yju3qc/L6SwqWo2Sw+54PX+PX0q9I+r1Um5HCmqD7n9VDX5/v3vQH/AjA6deDdtw==",
|
|
4374
|
+
"license": "MIT"
|
|
4375
|
+
},
|
|
4280
4376
|
"node_modules/undici-types": {
|
|
4281
4377
|
"version": "6.21.0",
|
|
4282
4378
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keyou007/agent-bot",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18-alpha.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Use Codex, TraeX, and compatible coding agents from Lark/Feishu.",
|
|
6
6
|
"license": "GPL-3.0-only",
|
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
"better-sqlite3": "12.11.1",
|
|
75
75
|
"dotenv": "17.4.2",
|
|
76
76
|
"highlight.js": "11.12.0",
|
|
77
|
+
"markdown-it": "15.0.1",
|
|
77
78
|
"pino": "10.3.1",
|
|
78
79
|
"yaml": "2.9.0",
|
|
79
80
|
"zod": "4.4.3"
|
|
@@ -6,6 +6,7 @@ import hljs from "highlight.js/lib/common";
|
|
|
6
6
|
import dos from "highlight.js/lib/languages/dos";
|
|
7
7
|
import dockerfile from "highlight.js/lib/languages/dockerfile";
|
|
8
8
|
import powershell from "highlight.js/lib/languages/powershell";
|
|
9
|
+
import MarkdownIt from "markdown-it";
|
|
9
10
|
import {
|
|
10
11
|
selectPreferredNetworkAddress,
|
|
11
12
|
type NetworkConnectionKind,
|
|
@@ -19,10 +20,27 @@ const MAX_TEXT_PREVIEW_BYTES = 2 * 1024 * 1024;
|
|
|
19
20
|
const MAX_CONTENT_SAMPLE_BYTES = 64 * 1024;
|
|
20
21
|
const MAX_SYNTAX_HIGHLIGHT_BYTES = 512 * 1024;
|
|
21
22
|
const DIRECTORY_PAGE_SIZE = 100;
|
|
23
|
+
const MARKDOWN_EXTENSIONS = new Set([".markdown", ".md", ".mdown", ".mkd", ".mkdn"]);
|
|
22
24
|
hljs.registerLanguage("dos", dos);
|
|
23
25
|
hljs.registerLanguage("dockerfile", dockerfile);
|
|
24
26
|
hljs.registerLanguage("powershell", powershell);
|
|
25
27
|
|
|
28
|
+
const MARKDOWN_RENDERER = new MarkdownIt({
|
|
29
|
+
breaks: false,
|
|
30
|
+
html: false,
|
|
31
|
+
linkify: true,
|
|
32
|
+
typographer: false,
|
|
33
|
+
highlight(value, language) {
|
|
34
|
+
const highlighted = language && hljs.getLanguage(language)
|
|
35
|
+
? hljs.highlight(value, { language, ignoreIllegals: true }).value
|
|
36
|
+
: escapeHtml(value);
|
|
37
|
+
const languageAttribute = language && hljs.getLanguage(language)
|
|
38
|
+
? ` class="language-${escapeAttribute(language)}"`
|
|
39
|
+
: "";
|
|
40
|
+
return `<pre class="markdown-code-block hljs"><code${languageAttribute}>${highlighted}</code></pre>`;
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
26
44
|
const HIGHLIGHT_LANGUAGE_BY_EXTENSION: Readonly<Record<string, string>> = {
|
|
27
45
|
".bash": "bash", ".bat": "dos", ".c": "c", ".cc": "cpp", ".cmd": "dos", ".cpp": "cpp",
|
|
28
46
|
".cs": "csharp", ".css": "css", ".cxx": "cpp", ".diff": "diff", ".go": "go", ".h": "cpp",
|
|
@@ -46,9 +64,31 @@ const VIEWER_CLIENT_SCRIPT = `(() => {
|
|
|
46
64
|
const metadata = document.getElementById("viewer-metadata");
|
|
47
65
|
const header = document.getElementById("viewer-header");
|
|
48
66
|
const title = document.getElementById("viewer-title");
|
|
67
|
+
const viewSwitch = document.getElementById("viewer-view-switch");
|
|
68
|
+
const viewButtons = Array.from(document.querySelectorAll("[data-view-mode-button]"));
|
|
49
69
|
if (!content || !metadata || !header || !title) return;
|
|
50
70
|
const filePath = title.dataset.filePath || title.textContent || "";
|
|
51
71
|
|
|
72
|
+
const syncViewMode = () => {
|
|
73
|
+
const mode = document.body.dataset.viewMode === "code" ? "code" : "rendered";
|
|
74
|
+
for (const button of viewButtons) {
|
|
75
|
+
const active = button.dataset.viewModeButton === mode;
|
|
76
|
+
button.classList.toggle("is-active", active);
|
|
77
|
+
button.setAttribute("aria-selected", String(active));
|
|
78
|
+
}
|
|
79
|
+
for (const panel of content.querySelectorAll("[data-view-panel]")) {
|
|
80
|
+
panel.setAttribute("aria-hidden", String(panel.dataset.viewPanel !== mode));
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
const setViewMode = (mode) => {
|
|
84
|
+
document.body.dataset.viewMode = mode === "code" ? "code" : "rendered";
|
|
85
|
+
syncViewMode();
|
|
86
|
+
if (mode === "code") requestAnimationFrame(positionHashTarget);
|
|
87
|
+
};
|
|
88
|
+
for (const button of viewButtons) {
|
|
89
|
+
button.addEventListener("click", () => setViewMode(button.dataset.viewModeButton));
|
|
90
|
+
}
|
|
91
|
+
|
|
52
92
|
title.addEventListener("pointerdown", (event) => {
|
|
53
93
|
if (event.button !== 0) return;
|
|
54
94
|
event.preventDefault();
|
|
@@ -83,6 +123,8 @@ const VIEWER_CLIENT_SCRIPT = `(() => {
|
|
|
83
123
|
const positionHashTarget = () => {
|
|
84
124
|
highlightHashTarget()?.scrollIntoView({ block: "start" });
|
|
85
125
|
};
|
|
126
|
+
if (/^#L\\d+$/u.test(window.location.hash)) document.body.dataset.viewMode = "code";
|
|
127
|
+
syncViewMode();
|
|
86
128
|
updateHeaderOffset();
|
|
87
129
|
if (typeof ResizeObserver === "function") {
|
|
88
130
|
new ResizeObserver(updateHeaderOffset).observe(header);
|
|
@@ -107,6 +149,7 @@ const VIEWER_CLIENT_SCRIPT = `(() => {
|
|
|
107
149
|
const codeScrollLeft = content.querySelector(".code")?.scrollLeft ?? 0;
|
|
108
150
|
content.innerHTML = nextContent;
|
|
109
151
|
metadata.innerHTML = nextMetadata;
|
|
152
|
+
syncViewMode();
|
|
110
153
|
highlightHashTarget();
|
|
111
154
|
restoreScroll(top, left, atBottom, codeScrollLeft);
|
|
112
155
|
};
|
|
@@ -116,6 +159,7 @@ const VIEWER_CLIENT_SCRIPT = `(() => {
|
|
|
116
159
|
try {
|
|
117
160
|
const update = JSON.parse(event.data);
|
|
118
161
|
if (typeof update.content === "string" && typeof update.metadata === "string") {
|
|
162
|
+
if (viewSwitch) viewSwitch.hidden = update.viewMode !== "markdown";
|
|
119
163
|
replaceContent(update.content, update.metadata);
|
|
120
164
|
}
|
|
121
165
|
} catch {
|
|
@@ -157,6 +201,7 @@ interface DirectoryViewerEntry {
|
|
|
157
201
|
interface RenderedFileSnapshot {
|
|
158
202
|
content: string;
|
|
159
203
|
metadata: string[];
|
|
204
|
+
viewMode?: "markdown";
|
|
160
205
|
}
|
|
161
206
|
|
|
162
207
|
export interface LocalFileViewerServerOptions {
|
|
@@ -423,6 +468,7 @@ export class LocalFileViewerServer {
|
|
|
423
468
|
{ href: downloadUrl.toString(), label: "下载" },
|
|
424
469
|
],
|
|
425
470
|
content: snapshot.content,
|
|
471
|
+
viewMode: snapshot.viewMode,
|
|
426
472
|
liveUpdates: {
|
|
427
473
|
eventsUrl: eventsUrl.toString(),
|
|
428
474
|
scriptPath: `${this.basePath}/assets/viewer.js`.replace(/\/{2,}/gu, "/"),
|
|
@@ -442,7 +488,10 @@ export class LocalFileViewerServer {
|
|
|
442
488
|
let content: string;
|
|
443
489
|
if (classification.kind === "text") {
|
|
444
490
|
const preview = readTextPreview(filePath, stat.size, classification.encoding);
|
|
445
|
-
|
|
491
|
+
const previewContent = isMarkdownFile(filePath)
|
|
492
|
+
? renderMarkdownDocument(preview.text, filePath)
|
|
493
|
+
: renderText(preview.text, filePath);
|
|
494
|
+
content = `${preview.truncated ? '<div class="notice">文件较大,仅显示开头 2 MiB。可使用下方按钮查看或下载完整文件。</div>' : ""}${previewContent}`;
|
|
446
495
|
} else if (contentType.startsWith("image/")) {
|
|
447
496
|
content = `<div class="media"><img src="${escapeAttribute(rawUrl.toString())}" alt="${escapeAttribute(fileName)}"></div>`;
|
|
448
497
|
} else if (contentType === "application/pdf") {
|
|
@@ -457,6 +506,9 @@ export class LocalFileViewerServer {
|
|
|
457
506
|
return {
|
|
458
507
|
content,
|
|
459
508
|
metadata: [formatFileSize(stat.size), stat.mtime.toLocaleString()],
|
|
509
|
+
...(classification.kind === "text" && isMarkdownFile(filePath)
|
|
510
|
+
? { viewMode: "markdown" as const }
|
|
511
|
+
: {}),
|
|
460
512
|
};
|
|
461
513
|
}
|
|
462
514
|
|
|
@@ -485,6 +537,7 @@ export class LocalFileViewerServer {
|
|
|
485
537
|
writeServerSentEvent(response, "update", JSON.stringify({
|
|
486
538
|
content: snapshot.content,
|
|
487
539
|
metadata: renderMetadata(snapshot.metadata),
|
|
540
|
+
viewMode: snapshot.viewMode ?? null,
|
|
488
541
|
}));
|
|
489
542
|
} catch {
|
|
490
543
|
writeServerSentEvent(response, "unavailable", JSON.stringify({
|
|
@@ -637,12 +690,19 @@ function renderViewerPage(input: {
|
|
|
637
690
|
metadata: string[];
|
|
638
691
|
actions: Array<{ href: string; label: string }>;
|
|
639
692
|
content: string;
|
|
693
|
+
viewMode?: "markdown";
|
|
640
694
|
liveUpdates?: { eventsUrl: string; scriptPath: string };
|
|
641
695
|
}): string {
|
|
642
696
|
const metadata = renderMetadata(input.metadata);
|
|
643
697
|
const actions = input.actions.length > 0
|
|
644
698
|
? `<nav class="actions">${input.actions.map((action) => `<a href="${escapeAttribute(action.href)}">${escapeHtml(action.label)}</a>`).join("")}</nav>`
|
|
645
699
|
: "";
|
|
700
|
+
const viewSwitch = input.viewMode === "markdown"
|
|
701
|
+
? '<div class="view-switch" id="viewer-view-switch" role="tablist" aria-label="预览模式"><button class="is-active" type="button" role="tab" aria-selected="true" data-view-mode-button="rendered">预览</button><button type="button" role="tab" aria-selected="false" data-view-mode-button="code">代码</button></div>'
|
|
702
|
+
: "";
|
|
703
|
+
const toolbar = viewSwitch || actions
|
|
704
|
+
? `<div class="toolbar">${viewSwitch}${actions}</div>`
|
|
705
|
+
: "";
|
|
646
706
|
const liveAttributes = input.liveUpdates
|
|
647
707
|
? ` data-events-url="${escapeAttribute(input.liveUpdates.eventsUrl)}"`
|
|
648
708
|
: "";
|
|
@@ -661,10 +721,15 @@ function renderViewerPage(input: {
|
|
|
661
721
|
body { margin: 0; background: #f5f7fa; color: #1f2329; }
|
|
662
722
|
header { position: sticky; top: 0; z-index: 2; padding: 7px 12px; background: rgba(255,255,255,.96); border-bottom: 1px solid #dfe3e8; }
|
|
663
723
|
h1 { margin: 0; cursor: text; font: 600 13px/1.4 ui-monospace, SFMono-Regular, Consolas, monospace; overflow-wrap: anywhere; }
|
|
664
|
-
.meta { display: flex; gap: 10px; align-items: center; min-height: 26px; margin-top: 3px; color: #646a73; font-size: 11px; }
|
|
724
|
+
.meta { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: center; min-height: 26px; margin-top: 3px; color: #646a73; font-size: 11px; }
|
|
665
725
|
.metadata-values { display: contents; }
|
|
666
|
-
.
|
|
726
|
+
.toolbar { margin-left: auto; display: flex; gap: 8px; align-items: center; }
|
|
727
|
+
.actions { display: flex; gap: 8px; }
|
|
667
728
|
.actions a { color: #1456f0; text-decoration: none; padding: 3px 7px; border: 1px solid #c9d0db; border-radius: 4px; background: #fff; }
|
|
729
|
+
.view-switch { display: inline-flex; padding: 2px; border: 1px solid #c9d0db; border-radius: 5px; background: #f2f3f5; }
|
|
730
|
+
.view-switch[hidden] { display: none; }
|
|
731
|
+
.view-switch button { min-width: 46px; padding: 2px 8px; border: 0; border-radius: 3px; background: transparent; color: #646a73; cursor: pointer; font: inherit; }
|
|
732
|
+
.view-switch button.is-active { background: #fff; color: #1456f0; box-shadow: 0 1px 3px rgba(31,35,41,.16); }
|
|
668
733
|
main { padding: 0; }
|
|
669
734
|
.notice, .unsupported { margin: 8px; padding: 10px 12px; border: 1px solid #f3cf8f; background: #fff7e6; border-radius: 5px; }
|
|
670
735
|
.code { margin: 0; padding: 6px 0; overflow: auto; border: 0; border-radius: 0; background: #fff; color: #1f2329; font-size: 13px; line-height: 1.5; tab-size: 2; }
|
|
@@ -681,6 +746,28 @@ function renderViewerPage(input: {
|
|
|
681
746
|
.hljs-addition { background: #e6ffed; }
|
|
682
747
|
.hljs-emphasis { font-style: italic; }
|
|
683
748
|
.hljs-strong { font-weight: 700; }
|
|
749
|
+
body[data-view-mode="rendered"] [data-view-panel="code"], body[data-view-mode="code"] [data-view-panel="rendered"] { display: none; }
|
|
750
|
+
.markdown-body { max-width: 980px; margin: 0 auto; padding: 20px 28px 48px; background: #fff; font-size: 15px; line-height: 1.72; overflow-wrap: anywhere; }
|
|
751
|
+
.markdown-body > :first-child { margin-top: 0; }
|
|
752
|
+
.markdown-body > :last-child { margin-bottom: 0; }
|
|
753
|
+
.markdown-body h1, .markdown-body h2, .markdown-body h3, .markdown-body h4, .markdown-body h5, .markdown-body h6 { margin: 1.45em 0 .6em; line-height: 1.28; }
|
|
754
|
+
.markdown-body h1 { padding-bottom: .35em; border-bottom: 1px solid #dfe3e8; font-size: 2em; }
|
|
755
|
+
.markdown-body h2 { padding-bottom: .3em; border-bottom: 1px solid #eceff3; font-size: 1.5em; }
|
|
756
|
+
.markdown-body h3 { font-size: 1.25em; }
|
|
757
|
+
.markdown-body p, .markdown-body ul, .markdown-body ol, .markdown-body blockquote, .markdown-body table, .markdown-body pre { margin: 0 0 1em; }
|
|
758
|
+
.markdown-body ul, .markdown-body ol { padding-left: 1.8em; }
|
|
759
|
+
.markdown-body li + li { margin-top: .28em; }
|
|
760
|
+
.markdown-body blockquote { margin-left: 0; padding: .15em 1em; border-left: 4px solid #c9d0db; color: #646a73; }
|
|
761
|
+
.markdown-body a { color: #1456f0; text-decoration: none; }
|
|
762
|
+
.markdown-body a:hover { text-decoration: underline; }
|
|
763
|
+
.markdown-body code { padding: .14em .35em; border-radius: 4px; background: #f2f3f5; font-family: var(--viewer-code-font); font-size: .9em; }
|
|
764
|
+
.markdown-body .markdown-code-block { margin: 0 0 1em; padding: 14px 16px; overflow: auto; border-radius: 6px; background: #f6f8fa; line-height: 1.55; }
|
|
765
|
+
.markdown-body .markdown-code-block code { padding: 0; background: transparent; font-size: 13px; }
|
|
766
|
+
.markdown-body table { display: block; max-width: 100%; overflow: auto; border-collapse: collapse; }
|
|
767
|
+
.markdown-body th, .markdown-body td { padding: 7px 12px; border: 1px solid #dfe3e8; text-align: left; }
|
|
768
|
+
.markdown-body th { background: #f5f7fa; }
|
|
769
|
+
.markdown-body img { max-width: 100%; height: auto; }
|
|
770
|
+
.markdown-body hr { height: 1px; margin: 1.5em 0; border: 0; background: #dfe3e8; }
|
|
684
771
|
.media { display: grid; place-items: center; min-height: 220px; }
|
|
685
772
|
.media img, .media video { max-width: 100%; max-height: calc(100vh - 70px); }
|
|
686
773
|
.media audio { width: min(720px, 100%); }
|
|
@@ -704,7 +791,19 @@ function renderViewerPage(input: {
|
|
|
704
791
|
.meta, .pagination { color: #a6a9ad; }
|
|
705
792
|
.actions a, .pagination a { color: #8ab4ff; }
|
|
706
793
|
.actions a { border-color: #55585c; background: #292a2d; }
|
|
794
|
+
.view-switch { border-color: #55585c; background: #292a2d; }
|
|
795
|
+
.view-switch button { color: #a6a9ad; }
|
|
796
|
+
.view-switch button.is-active { background: #3a3b3d; color: #8ab4ff; box-shadow: none; }
|
|
707
797
|
.code, .directory-list { background: #202124; color: #e8eaed; border-color: #3a3b3d; }
|
|
798
|
+
.markdown-body { background: #202124; color: #e8eaed; }
|
|
799
|
+
.markdown-body h1, .markdown-body h2 { border-color: #3a3b3d; }
|
|
800
|
+
.markdown-body blockquote { color: #a6a9ad; border-color: #55585c; }
|
|
801
|
+
.markdown-body a { color: #8ab4ff; }
|
|
802
|
+
.markdown-body code { background: #303134; }
|
|
803
|
+
.markdown-body .markdown-code-block { background: #282a2d; }
|
|
804
|
+
.markdown-body th, .markdown-body td { border-color: #55585c; }
|
|
805
|
+
.markdown-body th { background: #292a2d; }
|
|
806
|
+
.markdown-body hr { background: #3a3b3d; }
|
|
708
807
|
.directory-entry { border-color: #3a3b3d; }
|
|
709
808
|
.directory-entry:hover { background: #292f3d; }
|
|
710
809
|
.line-number { color: #8b9098; border-color: #3a3b3d; }
|
|
@@ -720,10 +819,10 @@ function renderViewerPage(input: {
|
|
|
720
819
|
}
|
|
721
820
|
</style>
|
|
722
821
|
</head>
|
|
723
|
-
<body${liveAttributes}>
|
|
822
|
+
<body${input.viewMode === "markdown" ? ' data-view-mode="rendered"' : ""}${liveAttributes}>
|
|
724
823
|
<header id="viewer-header">
|
|
725
824
|
<h1 id="viewer-title" data-file-path="${escapeAttribute(input.filePath)}">${escapeHtml(input.filePath)}</h1>
|
|
726
|
-
<div class="meta"><span class="metadata-values" id="viewer-metadata">${metadata}</span>${
|
|
825
|
+
<div class="meta"><span class="metadata-values" id="viewer-metadata">${metadata}</span>${toolbar}</div>
|
|
727
826
|
</header>
|
|
728
827
|
<main id="viewer-content">${input.content}</main>
|
|
729
828
|
${liveScript}
|
|
@@ -976,6 +1075,14 @@ function renderText(value: string, filePath: string): string {
|
|
|
976
1075
|
}).join("")}</code></pre>`;
|
|
977
1076
|
}
|
|
978
1077
|
|
|
1078
|
+
function renderMarkdownDocument(value: string, filePath: string): string {
|
|
1079
|
+
return `<article class="markdown-body" data-view-panel="rendered">${MARKDOWN_RENDERER.render(value)}</article><section data-view-panel="code">${renderText(value, filePath)}</section>`;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
function isMarkdownFile(filePath: string): boolean {
|
|
1083
|
+
return MARKDOWN_EXTENSIONS.has(path.extname(filePath).toLowerCase());
|
|
1084
|
+
}
|
|
1085
|
+
|
|
979
1086
|
function syntaxLanguageFor(filePath: string): string | undefined {
|
|
980
1087
|
const fileName = path.basename(filePath).toLowerCase();
|
|
981
1088
|
return HIGHLIGHT_LANGUAGE_BY_FILENAME[fileName]
|
|
@@ -1757,7 +1757,7 @@ export class ProxySessionController {
|
|
|
1757
1757
|
}
|
|
1758
1758
|
switch (command.type) {
|
|
1759
1759
|
case "shell":
|
|
1760
|
-
await this.runShellCommand(contextKey, command.command, messageId);
|
|
1760
|
+
await this.runShellCommand(contextKey, command.command, messageId, incomingMessage);
|
|
1761
1761
|
return;
|
|
1762
1762
|
case "dir":
|
|
1763
1763
|
await this.openDirectoryBrowser(contextKey, command.directory);
|
|
@@ -4963,8 +4963,9 @@ export class ProxySessionController {
|
|
|
4963
4963
|
contextKey: string,
|
|
4964
4964
|
command: string,
|
|
4965
4965
|
sourceMessageId?: string,
|
|
4966
|
+
incomingMessage?: IncomingMessage,
|
|
4966
4967
|
): Promise<void> {
|
|
4967
|
-
const cwd = this.
|
|
4968
|
+
const cwd = this.shellCommandCwd(contextKey, incomingMessage);
|
|
4968
4969
|
const created = await this.shellCommandJobs.createJob({ contextKey, sourceMessageId, command, cwd });
|
|
4969
4970
|
let cardMessageId: string | undefined;
|
|
4970
4971
|
const initialState: ShellCommandCardView = {
|
|
@@ -5010,6 +5011,28 @@ export class ProxySessionController {
|
|
|
5010
5011
|
}
|
|
5011
5012
|
}
|
|
5012
5013
|
|
|
5014
|
+
private shellCommandCwd(contextKey: string, incomingMessage?: IncomingMessage): string {
|
|
5015
|
+
const current = this.currentSession(contextKey);
|
|
5016
|
+
if (current) return current.cwd;
|
|
5017
|
+
|
|
5018
|
+
if (incomingMessage?.threadContext) {
|
|
5019
|
+
const anchor = threadForkAnchorMessageIds(incomingMessage)
|
|
5020
|
+
.map((messageId) => this.store.findTurnAnchorByMessageId(messageId))
|
|
5021
|
+
.find((candidate) => candidate !== undefined);
|
|
5022
|
+
const source = anchor?.contextKey
|
|
5023
|
+
? this.store.getSessionForContext(anchor.localSessionId, anchor.contextKey)
|
|
5024
|
+
: anchor
|
|
5025
|
+
? this.store.getSession(anchor.localSessionId)
|
|
5026
|
+
: undefined;
|
|
5027
|
+
const sourceContextKey = anchor?.contextKey ?? source?.contextKey;
|
|
5028
|
+
if (source && sourceContextKey && baseChatContextKey(sourceContextKey) === baseChatContextKey(contextKey)) {
|
|
5029
|
+
return source.cwd;
|
|
5030
|
+
}
|
|
5031
|
+
}
|
|
5032
|
+
|
|
5033
|
+
return this.config.defaults.cwd;
|
|
5034
|
+
}
|
|
5035
|
+
|
|
5013
5036
|
private monitorShellCommandJob(
|
|
5014
5037
|
job: ShellCommandJobSnapshot,
|
|
5015
5038
|
seededState?: ShellCommandCardView,
|