@nimbus-sh/worker 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/loaders/loader-pool.d.ts +7 -0
- package/dist/loaders/loader-pool.d.ts.map +1 -1
- package/dist/loaders/loader-pool.js +3 -1
- package/dist/runtime/clang-runner.d.ts +2 -2
- package/dist/runtime/clang-runner.d.ts.map +1 -1
- package/dist/runtime/clang-runner.js +63 -39
- package/dist/runtime/package-manager.d.ts +31 -0
- package/dist/runtime/package-manager.d.ts.map +1 -1
- package/dist/runtime/package-manager.js +132 -10
- package/dist/runtime/python-repl.d.ts +1 -0
- package/dist/runtime/python-repl.d.ts.map +1 -1
- package/dist/runtime/python-repl.js +8 -4
- package/dist/runtime/python-runner.d.ts.map +1 -1
- package/dist/runtime/python-runner.js +86 -82
- package/dist/session/init.d.ts.map +1 -1
- package/dist/session/init.js +49 -3
- package/dist/session/nimbus-session.d.ts +1 -0
- package/dist/session/nimbus-session.d.ts.map +1 -1
- package/dist/session/nimbus-session.js +49 -23
- package/dist/shell/unix-commands.d.ts.map +1 -1
- package/dist/shell/unix-commands.js +44 -39
- package/package.json +1 -1
- package/public/s/index.html +169 -7
package/public/s/index.html
CHANGED
|
@@ -101,6 +101,48 @@
|
|
|
101
101
|
.preview-bar button { background: none; border: none; color: #8b949e; cursor: pointer; font-size: 14px; padding: 2px 4px; }
|
|
102
102
|
.preview-bar button:hover { color: #c9d1d9; }
|
|
103
103
|
#preview-frame { flex: 1; border: none; background: white; width: 100%; }
|
|
104
|
+
#markdown-preview {
|
|
105
|
+
display: none; flex: 1; min-height: 0; overflow: auto;
|
|
106
|
+
background: #0d1117; color: #c9d1d9;
|
|
107
|
+
}
|
|
108
|
+
#markdown-preview.active { display: block; }
|
|
109
|
+
.markdown-body {
|
|
110
|
+
max-width: 860px; margin: 0 auto; padding: 34px 44px 56px;
|
|
111
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
|
|
112
|
+
font-size: 14px; line-height: 1.65;
|
|
113
|
+
}
|
|
114
|
+
.markdown-body h1, .markdown-body h2, .markdown-body h3 {
|
|
115
|
+
color: #f0f6fc; line-height: 1.25; margin: 24px 0 12px;
|
|
116
|
+
border-bottom: 1px solid #30363d; padding-bottom: 8px;
|
|
117
|
+
}
|
|
118
|
+
.markdown-body h1 { font-size: 30px; margin-top: 0; }
|
|
119
|
+
.markdown-body h2 { font-size: 22px; }
|
|
120
|
+
.markdown-body h3 { font-size: 18px; border-bottom: 0; padding-bottom: 0; }
|
|
121
|
+
.markdown-body p, .markdown-body ul, .markdown-body ol, .markdown-body table,
|
|
122
|
+
.markdown-body pre, .markdown-body blockquote { margin: 0 0 16px; }
|
|
123
|
+
.markdown-body a { color: #58a6ff; text-decoration: none; }
|
|
124
|
+
.markdown-body a:hover { text-decoration: underline; }
|
|
125
|
+
.markdown-body code {
|
|
126
|
+
background: rgba(110, 118, 129, 0.28); color: #f0f6fc;
|
|
127
|
+
border-radius: 4px; padding: 0.15em 0.35em;
|
|
128
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
129
|
+
font-size: 0.92em;
|
|
130
|
+
}
|
|
131
|
+
.markdown-body pre {
|
|
132
|
+
background: #161b22; border: 1px solid #30363d; border-radius: 6px;
|
|
133
|
+
padding: 14px 16px; overflow: auto;
|
|
134
|
+
}
|
|
135
|
+
.markdown-body pre code { background: transparent; padding: 0; color: #c9d1d9; }
|
|
136
|
+
.markdown-body blockquote {
|
|
137
|
+
border-left: 3px solid #3fb950; color: #8b949e; padding: 4px 0 4px 14px;
|
|
138
|
+
}
|
|
139
|
+
.markdown-body table { border-collapse: collapse; width: 100%; display: block; overflow: auto; }
|
|
140
|
+
.markdown-body th, .markdown-body td {
|
|
141
|
+
border: 1px solid #30363d; padding: 7px 10px; text-align: left;
|
|
142
|
+
}
|
|
143
|
+
.markdown-body th { background: #161b22; color: #f0f6fc; }
|
|
144
|
+
.markdown-body tr:nth-child(2n) td { background: rgba(22, 27, 34, 0.5); }
|
|
145
|
+
.markdown-body hr { border: 0; border-top: 1px solid #30363d; margin: 24px 0; }
|
|
104
146
|
|
|
105
147
|
/* Footer */
|
|
106
148
|
.footer { padding: 3px 12px; background: #161b22; border-top: 1px solid #30363d; font-size: 11px; color: #8b949e; flex-shrink: 0; display: flex; justify-content: space-between; gap: 12px; }
|
|
@@ -372,6 +414,9 @@
|
|
|
372
414
|
<button id="btnReloadPreview" title="Reload">↻</button>
|
|
373
415
|
</div>
|
|
374
416
|
<iframe id="preview-frame" src="about:blank"></iframe>
|
|
417
|
+
<div id="markdown-preview" aria-label="Markdown preview">
|
|
418
|
+
<article class="markdown-body" id="markdown-preview-body"></article>
|
|
419
|
+
</div>
|
|
375
420
|
</div>
|
|
376
421
|
</div>
|
|
377
422
|
<!-- Ctrl+P command palette. Lazy-populated fuzzy file finder; fs-list
|
|
@@ -475,6 +520,8 @@
|
|
|
475
520
|
const stText = document.getElementById('statusText');
|
|
476
521
|
const previewFrame = document.getElementById('preview-frame');
|
|
477
522
|
const previewPanel = document.getElementById('previewPanel');
|
|
523
|
+
const markdownPreview = document.getElementById('markdown-preview');
|
|
524
|
+
const markdownPreviewBody = document.getElementById('markdown-preview-body');
|
|
478
525
|
const mainPanel = document.getElementById('mainPanel');
|
|
479
526
|
const viteStatus = document.getElementById('viteStatus');
|
|
480
527
|
let ws = null, rd = 1000, statsTimer = null;
|
|
@@ -497,8 +544,11 @@
|
|
|
497
544
|
// Lazy-init Monaco + the file tree the FIRST time the user
|
|
498
545
|
// switches to editor mode. Cold session pays neither cost.
|
|
499
546
|
if (wantEditor) {
|
|
500
|
-
Editor.ensureLoaded();
|
|
501
|
-
FileTree.ensureLoaded();
|
|
547
|
+
const editorReady = Editor.ensureLoaded();
|
|
548
|
+
const treeReady = FileTree.ensureLoaded();
|
|
549
|
+
Promise.allSettled([editorReady, treeReady])
|
|
550
|
+
.then(() => Editor.openDefaultWelcome())
|
|
551
|
+
.catch(() => {});
|
|
502
552
|
}
|
|
503
553
|
setTimeout(() => {
|
|
504
554
|
// Re-apply persisted pane dims for this layout.
|
|
@@ -550,11 +600,13 @@
|
|
|
550
600
|
// race on the same path.
|
|
551
601
|
const pending = new Map();
|
|
552
602
|
let nextReqId = 1;
|
|
603
|
+
const DEFAULT_WELCOME_PATH = '/home/user/welcome.md';
|
|
553
604
|
|
|
554
605
|
// Current open file state.
|
|
555
606
|
let openPath = null; // POSIX absolute path or null
|
|
556
607
|
let originalContent = ''; // last-saved content (for dirty check)
|
|
557
608
|
let editor = null; // Monaco editor instance
|
|
609
|
+
let markdownUpdateTimer = null;
|
|
558
610
|
|
|
559
611
|
function tabEl() { return document.getElementById('editorTab'); }
|
|
560
612
|
function setTabFile(path, dirty) {
|
|
@@ -668,6 +720,20 @@
|
|
|
668
720
|
return map[ext] || 'plaintext';
|
|
669
721
|
}
|
|
670
722
|
|
|
723
|
+
function isMarkdownPath(path) {
|
|
724
|
+
return /\.(md|markdown|mdown|mkdn)$/i.test(path || '');
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
function scheduleMarkdownPreviewUpdate(content) {
|
|
728
|
+
if (!openPath || !isMarkdownPath(openPath)) return;
|
|
729
|
+
if (markdownUpdateTimer) clearTimeout(markdownUpdateTimer);
|
|
730
|
+
markdownUpdateTimer = setTimeout(() => {
|
|
731
|
+
showMarkdownPreview(openPath, content).catch((e) => {
|
|
732
|
+
setStatusFlash('markdown preview failed: ' + (e?.message || e));
|
|
733
|
+
});
|
|
734
|
+
}, 160);
|
|
735
|
+
}
|
|
736
|
+
|
|
671
737
|
function ensureLoaded() {
|
|
672
738
|
if (loaded) return Promise.resolve();
|
|
673
739
|
if (loading) return loading;
|
|
@@ -803,6 +869,9 @@
|
|
|
803
869
|
if (typeof FileTree !== 'undefined') {
|
|
804
870
|
try { FileTree.markDirty(openPath, dirty); } catch {}
|
|
805
871
|
}
|
|
872
|
+
if (isMarkdownPath(openPath)) {
|
|
873
|
+
scheduleMarkdownPreviewUpdate(cur);
|
|
874
|
+
}
|
|
806
875
|
});
|
|
807
876
|
// Cursor position → status bar.
|
|
808
877
|
const statusPos = document.getElementById('editorStatusPos');
|
|
@@ -823,7 +892,7 @@
|
|
|
823
892
|
setTimeout(() => editor.layout(), 0);
|
|
824
893
|
}
|
|
825
894
|
|
|
826
|
-
async function openFile(path) {
|
|
895
|
+
async function openFile(path, options = {}) {
|
|
827
896
|
if (!path) return;
|
|
828
897
|
// Dirty-prompt before switching files. If the current buffer has
|
|
829
898
|
// unsaved changes, ask the user whether to save or discard.
|
|
@@ -880,6 +949,13 @@
|
|
|
880
949
|
if (typeof FileTree !== 'undefined') {
|
|
881
950
|
try { FileTree.setSelected(path); FileTree.markDirty(path, false); } catch {}
|
|
882
951
|
}
|
|
952
|
+
if (isMarkdownPath(path)) {
|
|
953
|
+
showMarkdownPreview(path, content).catch((e) => {
|
|
954
|
+
setStatusFlash('markdown preview failed: ' + (e?.message || e));
|
|
955
|
+
});
|
|
956
|
+
} else if (!options.keepMarkdownPreview) {
|
|
957
|
+
showAppPreview();
|
|
958
|
+
}
|
|
883
959
|
editor.focus();
|
|
884
960
|
}
|
|
885
961
|
|
|
@@ -1027,7 +1103,21 @@
|
|
|
1027
1103
|
fileListCachedAt = 0;
|
|
1028
1104
|
}
|
|
1029
1105
|
|
|
1030
|
-
|
|
1106
|
+
function openDefaultWelcome() {
|
|
1107
|
+
if (openPath) return Promise.resolve();
|
|
1108
|
+
return openFile(DEFAULT_WELCOME_PATH);
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
function refreshMarkdownPreview() {
|
|
1112
|
+
if (!openPath || !editor || !isMarkdownPath(openPath)) return Promise.resolve();
|
|
1113
|
+
return showMarkdownPreview(openPath, editor.getValue());
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
return {
|
|
1117
|
+
ensureLoaded, openFile, save, openPalette, tryHandleFsResult,
|
|
1118
|
+
drainFsQueue, invalidateFileListCache, openDefaultWelcome,
|
|
1119
|
+
refreshMarkdownPreview,
|
|
1120
|
+
};
|
|
1031
1121
|
})();
|
|
1032
1122
|
|
|
1033
1123
|
// ── FileTree module ──
|
|
@@ -1600,30 +1690,102 @@
|
|
|
1600
1690
|
// applyPreviewTarget call always paints (even if nothing is running
|
|
1601
1691
|
// yet — that still wants the VITE_URL placeholder loaded).
|
|
1602
1692
|
let activePreview = null; // null | 'vite' | 'worker' | 'none'
|
|
1693
|
+
let previewSurface = 'app'; // 'app' | 'markdown'
|
|
1694
|
+
let markdownRendererPromise = null;
|
|
1695
|
+
let markdownRenderer = null;
|
|
1603
1696
|
|
|
1604
1697
|
function previewUrlFor(kind) {
|
|
1605
1698
|
return kind === 'worker' ? WORKER_URL : VITE_URL;
|
|
1606
1699
|
}
|
|
1607
1700
|
|
|
1701
|
+
function setPreviewUrlBar(value) {
|
|
1702
|
+
const urlBar = document.getElementById('urlBar');
|
|
1703
|
+
if (urlBar) urlBar.value = value;
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
function showAppPreview() {
|
|
1707
|
+
previewSurface = 'app';
|
|
1708
|
+
if (markdownPreview) markdownPreview.classList.remove('active');
|
|
1709
|
+
if (previewFrame) previewFrame.style.display = 'block';
|
|
1710
|
+
previewPanel.classList.remove('markdown-mode');
|
|
1711
|
+
const kind = (activePreview === null || activePreview === 'none') ? 'vite' : activePreview;
|
|
1712
|
+
const url = previewUrlFor(kind);
|
|
1713
|
+
if (previewFrame && (previewFrame.src === 'about:blank' || !previewFrame.src.includes(url))) {
|
|
1714
|
+
previewFrame.src = url;
|
|
1715
|
+
}
|
|
1716
|
+
setPreviewUrlBar(url);
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
async function showMarkdownPreview(path, markdown) {
|
|
1720
|
+
previewSurface = 'markdown';
|
|
1721
|
+
previewPanel.classList.add('markdown-mode');
|
|
1722
|
+
if (previewFrame) previewFrame.style.display = 'none';
|
|
1723
|
+
if (markdownPreview) markdownPreview.classList.add('active');
|
|
1724
|
+
setPreviewUrlBar('Markdown Preview · ' + path);
|
|
1725
|
+
const html = await renderMarkdown(markdown || '');
|
|
1726
|
+
if (markdownPreviewBody) markdownPreviewBody.innerHTML = html;
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
async function renderMarkdown(markdown) {
|
|
1730
|
+
try {
|
|
1731
|
+
const renderer = await ensureMarkdownRenderer();
|
|
1732
|
+
const raw = renderer.marked(markdown, { gfm: true, breaks: false });
|
|
1733
|
+
return renderer.purifier.sanitize(raw, { USE_PROFILES: { html: true } });
|
|
1734
|
+
} catch (e) {
|
|
1735
|
+
return '<pre><code>' + escapeHtml(markdown) + '</code></pre>';
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
function ensureMarkdownRenderer() {
|
|
1740
|
+
if (markdownRenderer) return Promise.resolve(markdownRenderer);
|
|
1741
|
+
if (markdownRendererPromise) return markdownRendererPromise;
|
|
1742
|
+
markdownRendererPromise = Promise.all([
|
|
1743
|
+
import('https://cdn.jsdelivr.net/npm/marked@12.0.2/+esm'),
|
|
1744
|
+
import('https://cdn.jsdelivr.net/npm/dompurify@3.1.7/+esm'),
|
|
1745
|
+
]).then(([markedModule, purifyModule]) => {
|
|
1746
|
+
const marked = markedModule.marked || markedModule.parse || markedModule.default;
|
|
1747
|
+
const createDOMPurify = purifyModule.default || purifyModule.DOMPurify || purifyModule;
|
|
1748
|
+
const purifier = typeof createDOMPurify === 'function'
|
|
1749
|
+
? createDOMPurify(window)
|
|
1750
|
+
: createDOMPurify;
|
|
1751
|
+
if (typeof marked !== 'function' || !purifier || typeof purifier.sanitize !== 'function') {
|
|
1752
|
+
throw new Error('markdown renderer unavailable');
|
|
1753
|
+
}
|
|
1754
|
+
markdownRenderer = { marked, purifier };
|
|
1755
|
+
return markdownRenderer;
|
|
1756
|
+
});
|
|
1757
|
+
return markdownRendererPromise;
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
function escapeHtml(s) {
|
|
1761
|
+
const div = document.createElement('div');
|
|
1762
|
+
div.textContent = String(s);
|
|
1763
|
+
return div.innerHTML;
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1608
1766
|
function applyPreviewTarget(kind) {
|
|
1609
1767
|
// Idempotent: only update iframe + URL bar when the backend kind
|
|
1610
1768
|
// actually changes. Avoids tearing down the inner app on every
|
|
1611
1769
|
// 5-second stats poll.
|
|
1612
|
-
if (activePreview === kind) return;
|
|
1770
|
+
if (activePreview === kind && previewSurface === 'app') return;
|
|
1613
1771
|
activePreview = kind;
|
|
1772
|
+
if (previewSurface !== 'app') return;
|
|
1614
1773
|
const url = previewUrlFor(kind);
|
|
1615
1774
|
// Always use the VITE_URL path when nothing is running — that
|
|
1616
1775
|
// endpoint serves the styled "no dev server" placeholder, which
|
|
1617
1776
|
// self-refreshes via its own polling loop.
|
|
1618
1777
|
previewFrame.src = url;
|
|
1619
|
-
|
|
1620
|
-
if (urlBar) urlBar.value = url;
|
|
1778
|
+
setPreviewUrlBar(url);
|
|
1621
1779
|
// If the user had collapsed the preview because nothing was up,
|
|
1622
1780
|
// surface it automatically when the first backend comes online.
|
|
1623
1781
|
if (kind !== 'none' && layout === 'terminal-only') setLayout('split');
|
|
1624
1782
|
}
|
|
1625
1783
|
|
|
1626
1784
|
function reloadPreview() {
|
|
1785
|
+
if (previewSurface === 'markdown') {
|
|
1786
|
+
Editor.refreshMarkdownPreview().catch(() => {});
|
|
1787
|
+
return;
|
|
1788
|
+
}
|
|
1627
1789
|
// Refreshing without a running backend should re-poll the
|
|
1628
1790
|
// placeholder so users see dev-server status update promptly.
|
|
1629
1791
|
if (previewFrame.src === 'about:blank' ||
|