ompchamber 0.7.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/index.html +1 -1
- package/dist/client/static/css/index.e880517fcd.css +2 -0
- package/dist/client/static/js/async/{3y.4c2596f64c.js → 3y.71f2ccf3b6.js} +2 -2
- package/dist/client/static/js/async/{xw.ae67ba06fd.js → 5b.0d6ae50fe8.js} +10 -10
- package/dist/client/static/js/async/5bh.8b2363424f.js +1 -0
- package/dist/client/static/js/async/{vy.bbe114c4e0.js → bi.09688ba75c.js} +1 -2
- package/dist/client/static/js/async/c.797d933882.js +1 -0
- package/dist/client/static/js/async/{dc.6dc4b0a04b.js → dc.856fda6560.js} +2 -2
- package/dist/client/static/js/async/g.a06ca3b3e9.js +2 -0
- package/dist/client/static/js/async/g.a06ca3b3e9.js.LICENSE.txt +11 -0
- package/dist/client/static/js/async/{m.4b29d34f93.js → m.c038c71b9f.js} +2 -2
- package/dist/client/static/js/async/ma.2c261b04dd.js +2 -0
- package/dist/client/static/js/async/ms.98960af4eb.js +67 -0
- package/dist/client/static/js/async/nam.b5663e919f.js +10 -0
- package/dist/client/static/js/async/nam.b5663e919f.js.LICENSE.txt +11 -0
- package/dist/client/static/js/async/ot.84c71b308f.js +2 -0
- package/dist/client/static/js/async/ot.84c71b308f.js.LICENSE.txt +11 -0
- package/dist/client/static/js/async/{q.542c184fec.js → q.23af2a358f.js} +3 -3
- package/dist/client/static/js/async/{s.413c2a4683.js → s.222ee974f6.js} +2 -2
- package/dist/client/static/js/async/t.4dca0e2ba8.js +1 -0
- package/dist/client/static/js/async/uf.46ad6209fa.js +2 -0
- package/dist/client/static/js/async/xn.6360379f71.js +2 -0
- package/dist/client/static/js/async/xnl.feb0021e50.js +2 -0
- package/dist/client/static/js/async/xnl.feb0021e50.js.LICENSE.txt +12 -0
- package/dist/client/static/js/index.0de15c5e17.js +33 -0
- package/dist/client/static/js/{uy.2e8929ed0c.js → jp.50817896f3.js} +6 -6
- package/package.json +2 -1
- package/src/client/components/common/MarkdownRenderer.tsx +69 -27
- package/src/client/components/common/code-editor/history.test.ts +118 -0
- package/src/client/components/common/code-editor/history.ts +101 -0
- package/src/client/components/common/code-editor/index.tsx +56 -66
- package/src/client/components/common/code-surface/index.tsx +84 -11
- package/src/client/components/common/code-surface/measure.ts +66 -17
- package/src/client/components/common/diagram-viewer/index.tsx +258 -0
- package/src/client/components/common/diagram-viewer/read-block.ts +53 -0
- package/src/client/components/layout/session-sidebar/CategoryItem.tsx +2 -1
- package/src/client/components/layout/session-sidebar/SessionItem.tsx +11 -4
- package/src/client/components/layout/session-sidebar/SessionList.tsx +1 -1
- package/src/client/components/mobile/mobile-session-sidebar/Item.tsx +1 -1
- package/src/client/components/mobile/mobile-session-sidebar/List.tsx +1 -1
- package/src/client/components/mobile/mobile-session-sidebar/SessionRow.tsx +2 -2
- package/src/client/components/settings/LazyModal.tsx +1 -1
- package/src/client/components/settings/Modal.tsx +2 -1
- package/src/client/components/workspace/chat-timeline/ComposerDock.tsx +11 -4
- package/src/client/components/workspace/chat-timeline/QueueList.tsx +18 -14
- package/src/client/components/workspace/chat-timeline/ToolCallCard.tsx +8 -1
- package/src/client/components/workspace/chat-timeline/chat-input/index.tsx +11 -52
- package/src/client/components/workspace/chat-timeline/chat-input/selection.ts +57 -0
- package/src/client/components/workspace/chat-timeline/index.tsx +124 -108
- package/src/client/components/workspace/chat-timeline/tool-renderers/ask-panel/FrameControl.tsx +172 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/ask-panel/QuestionBlock.tsx +155 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/ask-panel/drafts.ts +113 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/ask-panel/index.tsx +92 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/{ask-dialog → extension-dialog}/Footer.tsx +3 -3
- package/src/client/components/workspace/chat-timeline/tool-renderers/{ask-dialog → extension-dialog}/Header.tsx +3 -3
- package/src/client/components/workspace/chat-timeline/tool-renderers/{ask-dialog → extension-dialog}/Lazy.tsx +8 -8
- package/src/client/components/workspace/chat-timeline/tool-renderers/{ask-dialog → extension-dialog}/SelectBody.tsx +3 -3
- package/src/client/components/workspace/chat-timeline/tool-renderers/{ask-dialog → extension-dialog}/index.tsx +16 -10
- package/src/client/components/workspace/chat-timeline/tool-renderers/index.tsx +2 -2
- package/src/client/components/workspace/file-explorer/index.tsx +18 -5
- package/src/client/components/workspace/git-panel/BranchToolbar.tsx +2 -2
- package/src/client/components/workspace/git-panel/index.tsx +5 -1
- package/src/client/components/workspace/terminal-panel/Header.tsx +51 -19
- package/src/client/components/workspace/terminal-panel/RealtimeXtermView.tsx +86 -282
- package/src/client/components/workspace/terminal-panel/index.tsx +76 -50
- package/src/client/components/workspace/terminal-panel/mount.ts +275 -0
- package/src/client/data/theme/terminal.ts +27 -29
- package/src/client/hooks/chat/omp/session-list.tsx +23 -2
- package/src/client/hooks/chat/omp/session-sidebar-controller.ts +1 -1
- package/src/client/hooks/chat/timeline/actions.ts +23 -34
- package/src/client/hooks/chat/timeline/ask-frames.ts +102 -0
- package/src/client/hooks/chat/timeline/extension-dialog.ts +12 -9
- package/src/client/hooks/chat/timeline/index.ts +18 -28
- package/src/client/hooks/chat/timeline/prompt-text.ts +35 -0
- package/src/client/hooks/chat/timeline/queue.ts +110 -46
- package/src/client/hooks/chat/timeline/send.ts +13 -27
- package/src/client/hooks/chat/timeline/session-load.ts +48 -106
- package/src/client/hooks/chat/timeline/session-pagination.ts +144 -0
- package/src/client/hooks/editor/use-code-window.ts +118 -0
- package/src/client/hooks/ui/input-required-alert.ts +43 -0
- package/src/client/hooks/ui/notification-sound.ts +65 -0
- package/src/client/hooks/ui/theme.ts +22 -6
- package/src/client/hooks/workspace/terminal/index.ts +217 -0
- package/src/client/hooks/workspace/terminal/socket.ts +227 -0
- package/src/client/tailwind.css +38 -12
- package/src/server/db.server.ts +19 -0
- package/src/server/lib/fs/git-sync.ts +191 -0
- package/src/server/lib/omp/rpc/manager.ts +72 -6
- package/src/server/lib/omp/rpc/session-commands.ts +6 -0
- package/src/server/lib/omp/rpc/session-registry.ts +18 -0
- package/src/server/lib/omp/session/sidebar-data.server.ts +10 -4
- package/src/server/lib/queue/delivery.server.ts +114 -0
- package/src/server/lib/queue/schema-migration.server.ts +50 -0
- package/src/server/lib/queue/store.server.ts +185 -0
- package/src/server/lib/terminal/foreground.ts +73 -0
- package/src/server/lib/terminal/history.test.ts +118 -0
- package/src/server/lib/terminal/history.ts +205 -0
- package/src/server/lib/terminal/runtime.server.ts +338 -0
- package/src/server/lib/terminal/session.server.ts +215 -0
- package/src/server/lib/terminal/shell.test.ts +97 -0
- package/src/server/lib/terminal/shell.ts +103 -0
- package/src/server/routes/fs/git.ts +22 -12
- package/src/server/routes/index.ts +2 -1
- package/src/server/routes/sessions/index.ts +11 -3
- package/src/server/routes/sessions/queue.ts +121 -0
- package/src/server/routes/sessions/session.ts +1 -132
- package/src/server/routes/settings/commands.ts +1 -1
- package/src/server/routes/terminal/index.ts +2 -2
- package/src/server/routes/terminal/run.ts +8 -100
- package/src/server/routes/terminal/sessions.ts +24 -0
- package/src/server/routes/terminal/ws.ts +149 -0
- package/src/shared/lib/chat/ask-questions.test.ts +169 -0
- package/src/shared/lib/chat/ask-questions.ts +264 -0
- package/src/shared/lib/chat/omp/agent-events.test.ts +37 -1
- package/src/shared/lib/chat/omp/agent-events.ts +30 -0
- package/src/shared/lib/chat/timeline/omp-callbacks.test.ts +9 -1
- package/src/shared/lib/chat/timeline/omp-callbacks.ts +45 -8
- package/src/shared/lib/code/lazy-window.test.ts +161 -0
- package/src/shared/lib/code/lazy-window.ts +156 -0
- package/src/shared/lib/code/syntax-highlight.test.ts +50 -1
- package/src/shared/lib/code/syntax-highlight.ts +14 -1
- package/src/shared/lib/code/windowed-highlight.ts +63 -0
- package/src/shared/lib/markdown/mermaid.ts +8 -6
- package/src/shared/lib/omp/session/stream-state.server.ts +2 -3
- package/src/shared/lib/workspace/session-state/store.ts +1 -4
- package/src/shared/lib/workspace/terminal/protocol.ts +222 -0
- package/src/shared/types/omp/agent.ts +14 -2
- package/src/shared/types/terminal.ts +17 -15
- package/src/shared/types/workspace.ts +6 -2
- package/dist/client/static/css/index.51f68210a5.css +0 -2
- package/dist/client/static/js/async/5b.d88304bc13.js +0 -1
- package/dist/client/static/js/async/c.cd45b0ac45.js +0 -1
- package/dist/client/static/js/async/fw.6a51998a8e.js +0 -6
- package/dist/client/static/js/async/g.86e2256a70.js +0 -2
- package/dist/client/static/js/async/kc.bbdb35b771.js +0 -1
- package/dist/client/static/js/async/mw.ca1512563c.js +0 -10
- package/dist/client/static/js/async/rf.d626afc367.js +0 -2
- package/dist/client/static/js/async/t.cda4891526.js +0 -1
- package/dist/client/static/js/async/uf.24ca3d49c3.js +0 -2
- package/dist/client/static/js/async/uf.24ca3d49c3.js.LICENSE.txt +0 -6
- package/dist/client/static/js/async/v0.394ed37c6b.js +0 -2
- package/dist/client/static/js/async/v0.394ed37c6b.js.LICENSE.txt +0 -6
- package/dist/client/static/js/async/vy.bbe114c4e0.js.LICENSE.txt +0 -6
- package/dist/client/static/js/async/xn.afecebbbd9.js +0 -2
- package/dist/client/static/js/index.eccad0b70a.js +0 -33
- package/dist/client/static/js/index.eccad0b70a.js.LICENSE.txt +0 -4
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Ask.tsx +0 -205
- package/src/client/components/workspace/terminal-panel/InputBar.tsx +0 -82
- package/src/client/components/workspace/terminal-panel/LogEntry.tsx +0 -70
- package/src/client/hooks/workspace/terminal-output.ts +0 -66
- package/src/client/hooks/workspace/terminal.ts +0 -283
- package/src/server/lib/fs/terminal-cwd.ts +0 -49
- package/src/server/routes/terminal/stream.ts +0 -100
- /package/dist/client/static/js/async/{3y.4c2596f64c.js.LICENSE.txt → 3y.71f2ccf3b6.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/async/{g.86e2256a70.js.LICENSE.txt → 5b.0d6ae50fe8.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/async/{dc.6dc4b0a04b.js.LICENSE.txt → dc.856fda6560.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/async/{fw.6a51998a8e.js.LICENSE.txt → m.c038c71b9f.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/async/{m.4b29d34f93.js.LICENSE.txt → ma.2c261b04dd.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/async/{xn.afecebbbd9.js.LICENSE.txt → ms.98960af4eb.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/async/{mw.ca1512563c.js.LICENSE.txt → q.23af2a358f.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/async/{q.542c184fec.js.LICENSE.txt → s.222ee974f6.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/async/{rf.d626afc367.js.LICENSE.txt → uf.46ad6209fa.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/async/{s.413c2a4683.js.LICENSE.txt → xn.6360379f71.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/{async/xw.ae67ba06fd.js.LICENSE.txt → index.0de15c5e17.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/{uy.2e8929ed0c.js.LICENSE.txt → jp.50817896f3.js.LICENSE.txt} +0 -0
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
|
|
3
3
|
import { AlertCircle, CheckCircle2, FileText, HelpCircle, ListFilter, Terminal } from 'lucide-preact';
|
|
4
4
|
import type { ExtensionUiDialogRequest } from '@/client/hooks/chat/omp';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
5
|
+
import { ExtensionDialogHeader } from '@/client/components/workspace/chat-timeline/tool-renderers/extension-dialog/Header';
|
|
6
|
+
import { ExtensionDialogSelectBody } from '@/client/components/workspace/chat-timeline/tool-renderers/extension-dialog/SelectBody';
|
|
7
|
+
import { ExtensionDialogFooter } from '@/client/components/workspace/chat-timeline/tool-renderers/extension-dialog/Footer';
|
|
8
8
|
import { MarkdownRenderer } from '@/client/components/common/MarkdownRenderer';
|
|
9
9
|
|
|
10
10
|
export type ExtensionDialogResponse =
|
|
@@ -12,12 +12,18 @@ export type ExtensionDialogResponse =
|
|
|
12
12
|
| { confirmed: boolean }
|
|
13
13
|
| { cancelled: true };
|
|
14
14
|
|
|
15
|
-
interface
|
|
15
|
+
interface ExtensionDialogProps {
|
|
16
16
|
request: ExtensionUiDialogRequest;
|
|
17
17
|
onRespond: (request: ExtensionUiDialogRequest, response: ExtensionDialogResponse) => void;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Blocking extension dialog that has no card of its own to render in: an
|
|
22
|
+
* approval gate under `always-ask`, or a picker an extension raised. The `ask`
|
|
23
|
+
* tool's own dialogs render inline on its tool card instead (see ask-panel) —
|
|
24
|
+
* a modal would only ever show the question currently in flight.
|
|
25
|
+
*/
|
|
26
|
+
export function ExtensionDialog({ request, onRespond }: ExtensionDialogProps) {
|
|
21
27
|
const [value, setValue] = useState(request.method === 'editor' ? request.prefill ?? '' : '');
|
|
22
28
|
const [selectedOption, setSelectedOption] = useState<string | null>(null);
|
|
23
29
|
const [customValue, setCustomValue] = useState('');
|
|
@@ -202,7 +208,7 @@ export function AskDialog({ request, onRespond }: AskDialogProps) {
|
|
|
202
208
|
|
|
203
209
|
return (
|
|
204
210
|
<div
|
|
205
|
-
className="
|
|
211
|
+
className="extension-dialog-backdrop fixed inset-0 z-50 flex items-center justify-center p-4 sm:p-6"
|
|
206
212
|
style={{
|
|
207
213
|
background: 'color-mix(in srgb, var(--theme-ink) 55%, transparent)',
|
|
208
214
|
backdropFilter: 'blur(8px)',
|
|
@@ -217,12 +223,12 @@ export function AskDialog({ request, onRespond }: AskDialogProps) {
|
|
|
217
223
|
aria-modal="true"
|
|
218
224
|
aria-label={request.title || methodMeta.label}
|
|
219
225
|
tabIndex={-1}
|
|
220
|
-
className="
|
|
226
|
+
className="extension-dialog-panel w-full max-w-[560px] overflow-hidden rounded-2xl border border-ink/15 bg-paper shadow-2xl outline-none"
|
|
221
227
|
style={{
|
|
222
228
|
boxShadow: '0 24px 64px -8px color-mix(in srgb, var(--theme-ink) 28%, transparent)',
|
|
223
229
|
}}
|
|
224
230
|
>
|
|
225
|
-
<
|
|
231
|
+
<ExtensionDialogHeader
|
|
226
232
|
title={request.title}
|
|
227
233
|
methodLabel={methodMeta.label}
|
|
228
234
|
badge={methodMeta.badge}
|
|
@@ -240,7 +246,7 @@ export function AskDialog({ request, onRespond }: AskDialogProps) {
|
|
|
240
246
|
|
|
241
247
|
{/* Select Options */}
|
|
242
248
|
{request.method === 'select' && (
|
|
243
|
-
<
|
|
249
|
+
<ExtensionDialogSelectBody
|
|
244
250
|
options={options}
|
|
245
251
|
optionDetails={optionDetails}
|
|
246
252
|
selectedOption={selectedOption}
|
|
@@ -307,7 +313,7 @@ export function AskDialog({ request, onRespond }: AskDialogProps) {
|
|
|
307
313
|
)}
|
|
308
314
|
</div>
|
|
309
315
|
|
|
310
|
-
<
|
|
316
|
+
<ExtensionDialogFooter
|
|
311
317
|
method={request.method}
|
|
312
318
|
optionsLength={options.length}
|
|
313
319
|
selectedOption={selectedOption}
|
|
@@ -19,7 +19,7 @@ import { AstEdit } from '@/client/components/workspace/chat-timeline/tool-render
|
|
|
19
19
|
import { Resolve } from '@/client/components/workspace/chat-timeline/tool-renderers/panels/Resolve';
|
|
20
20
|
import { ManageSkill } from '@/client/components/workspace/chat-timeline/tool-renderers/panels/ManageSkill';
|
|
21
21
|
import { SearchFs } from '@/client/components/workspace/chat-timeline/tool-renderers/panels/SearchFs';
|
|
22
|
-
import {
|
|
22
|
+
import { AskPanel } from '@/client/components/workspace/chat-timeline/tool-renderers/ask-panel';
|
|
23
23
|
import { Think } from '@/client/components/workspace/chat-timeline/tool-renderers/panels/Think';
|
|
24
24
|
import { Read } from '@/client/components/workspace/chat-timeline/tool-renderers/panels/Read';
|
|
25
25
|
import { Edit } from '@/client/components/workspace/chat-timeline/tool-renderers/panels/Edit';
|
|
@@ -142,7 +142,7 @@ export function ToolDetailsPanel({ tool }: { tool: ToolCallData }): ReactNode {
|
|
|
142
142
|
return <Memory tool={tool} />;
|
|
143
143
|
}
|
|
144
144
|
if (key === 'goal' || key === 'yield') return <Goal tool={tool} />;
|
|
145
|
-
if (key === 'ask') return <
|
|
145
|
+
if (key === 'ask') return <AskPanel tool={tool} />;
|
|
146
146
|
if (key === 'think') return <Think tool={tool} />;
|
|
147
147
|
|
|
148
148
|
// Dynamic MCP / custom tools — `mcp__<tool>` names and xd:// device writes
|
|
@@ -63,15 +63,28 @@ export function FileExplorer({ className = '', enabled = true, rootPath, onOpenF
|
|
|
63
63
|
loadFiles();
|
|
64
64
|
}, [refreshKey, rootPath, enabled, activeRepo, expandedPathsReady]);
|
|
65
65
|
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
|
|
66
|
+
// The listing and its git decorations describe the same working tree, so one
|
|
67
|
+
// refresh drives both. Re-reading only the tree left every folder dot stale:
|
|
68
|
+
// `useGitStatus` has no poll of its own in this panel, so a new/changed file
|
|
69
|
+
// appeared under a folder that still claimed a clean status until the user
|
|
70
|
+
// hit refresh or refocused the window.
|
|
71
|
+
const refreshListing = () => {
|
|
72
|
+
loadFiles({ silent: true });
|
|
73
|
+
refreshGitStatus();
|
|
74
|
+
};
|
|
75
|
+
// Auto refresh: re-read on a cadence so external changes (terminal output,
|
|
76
|
+
// agent edits) surface without a manual refresh. Silent — the loading
|
|
77
|
+
// spinner stays reserved for the user's own refresh button.
|
|
78
|
+
usePanelRefresh(refreshListing, enabled && expandedPathsReady);
|
|
70
79
|
// AI edits land between poll ticks: re-read right after a file-mutating tool
|
|
71
80
|
// (edit / write / ast_edit / bash) finishes, not up to 2s later.
|
|
72
|
-
useFileMutationRefresh(
|
|
81
|
+
useFileMutationRefresh(refreshListing, enabled && expandedPathsReady);
|
|
73
82
|
|
|
74
83
|
const loadChildren = (path: string) => {
|
|
84
|
+
// Expanding IS a directory load: fetch the children AND re-read git status,
|
|
85
|
+
// so a freshly listed row never renders bare next to a status map that
|
|
86
|
+
// still predates its change (the panel poll alone can lag a fresh edit).
|
|
87
|
+
refreshGitStatus();
|
|
75
88
|
return fetch(listUrl(path))
|
|
76
89
|
.then(r => r.json())
|
|
77
90
|
.then(data => {
|
|
@@ -113,7 +113,7 @@ export function GitBranchToolbar({
|
|
|
113
113
|
<button
|
|
114
114
|
type="button"
|
|
115
115
|
onClick={onSync}
|
|
116
|
-
disabled={isBusy
|
|
116
|
+
disabled={isBusy}
|
|
117
117
|
title={
|
|
118
118
|
syncCount.ahead > 0 && syncCount.behind > 0
|
|
119
119
|
? `Pull ${syncCount.behind} then push ${syncCount.ahead} commit(s)`
|
|
@@ -121,7 +121,7 @@ export function GitBranchToolbar({
|
|
|
121
121
|
? `Push ${syncCount.ahead} commit(s)`
|
|
122
122
|
: syncCount.behind > 0
|
|
123
123
|
? `Pull ${syncCount.behind} commit(s)`
|
|
124
|
-
: 'Up to date'
|
|
124
|
+
: 'Up to date — sync anyway'
|
|
125
125
|
}
|
|
126
126
|
className="flex items-center gap-1 p-1 rounded hover:text-ink hover:bg-ink/5 cursor-pointer transition-colors disabled:opacity-40 disabled:cursor-not-allowed"
|
|
127
127
|
>
|
|
@@ -34,6 +34,10 @@ export function GitPanel({ className = '', enabled = true, rootPath, refreshKey
|
|
|
34
34
|
const params = new URLSearchParams();
|
|
35
35
|
if (rootPath) params.set('root', rootPath);
|
|
36
36
|
if (targetRepo && targetRepo !== '.') params.set('repo', targetRepo);
|
|
37
|
+
// The toolbar's ↑ahead ↓behind badge is what this asks for; it makes the
|
|
38
|
+
// loader refresh the branch's remote-tracking ref before counting, so the
|
|
39
|
+
// numbers describe origin rather than the last fetch.
|
|
40
|
+
params.set('sync', '1');
|
|
37
41
|
params.set('t', String(Date.now()));
|
|
38
42
|
fetcher.load(`/api/fs/git?${params.toString()}`);
|
|
39
43
|
};
|
|
@@ -200,7 +204,7 @@ export function GitPanel({ className = '', enabled = true, rootPath, refreshKey
|
|
|
200
204
|
if (!enabled || pollingRepos || rescanningRepos) return;
|
|
201
205
|
setExtraRepos(repos);
|
|
202
206
|
setRescanningRepos(true);
|
|
203
|
-
const params = new URLSearchParams({ rescan: '1' });
|
|
207
|
+
const params = new URLSearchParams({ rescan: '1', sync: '1' });
|
|
204
208
|
if (rootPath) params.set('root', rootPath);
|
|
205
209
|
if (activeRepo !== '.') params.set('repo', activeRepo);
|
|
206
210
|
params.set('t', String(Date.now()));
|
|
@@ -1,23 +1,46 @@
|
|
|
1
|
-
import { Loader2, Terminal } from 'lucide-preact';
|
|
1
|
+
import { Loader2, RotateCw, Terminal } from 'lucide-preact';
|
|
2
2
|
import { GitRepoDropdown } from '@/client/components/workspace/file-explorer/GitRepoDropdown';
|
|
3
|
+
import type { TerminalStatus } from '@/client/hooks/workspace/terminal';
|
|
3
4
|
|
|
4
5
|
interface TerminalHeaderProps {
|
|
5
|
-
|
|
6
|
+
status: TerminalStatus;
|
|
7
|
+
exitCode: number | null;
|
|
6
8
|
rootPath?: string;
|
|
7
9
|
activeRepo: string;
|
|
8
10
|
onSelectRepo: (repo: string) => void;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
/** Working directory the shell actually runs in. */
|
|
12
|
+
cwd?: string;
|
|
13
|
+
shell?: string;
|
|
14
|
+
gitBranch?: string;
|
|
15
|
+
onRestart: () => void;
|
|
11
16
|
}
|
|
12
17
|
|
|
18
|
+
const STATUS_LABEL: Record<TerminalStatus, string> = {
|
|
19
|
+
connecting: 'CONNECTING',
|
|
20
|
+
running: 'LIVE',
|
|
21
|
+
exited: 'EXITED',
|
|
22
|
+
error: 'ERROR',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const STATUS_CLASS: Record<TerminalStatus, string> = {
|
|
26
|
+
connecting: 'bg-warning/10 text-warning border-warning/20',
|
|
27
|
+
running: 'bg-success/10 text-success border-success/20',
|
|
28
|
+
exited: 'bg-ink/5 text-ink/60 border-ink/15',
|
|
29
|
+
error: 'bg-error/10 text-error border-error/20',
|
|
30
|
+
};
|
|
31
|
+
|
|
13
32
|
export function TerminalHeader({
|
|
14
|
-
|
|
33
|
+
status,
|
|
34
|
+
exitCode,
|
|
15
35
|
rootPath,
|
|
16
36
|
activeRepo,
|
|
17
37
|
onSelectRepo,
|
|
18
|
-
|
|
19
|
-
|
|
38
|
+
cwd,
|
|
39
|
+
shell,
|
|
40
|
+
gitBranch,
|
|
41
|
+
onRestart,
|
|
20
42
|
}: TerminalHeaderProps) {
|
|
43
|
+
const shellName = shell ? shell.split('/').pop() : '';
|
|
21
44
|
return (
|
|
22
45
|
<div className="h-10 px-3 border-b border-ink/10 bg-paper flex items-center justify-between flex-shrink-0 select-none">
|
|
23
46
|
{/* Left cluster: Title, Status, Repo */}
|
|
@@ -29,22 +52,31 @@ export function TerminalHeader({
|
|
|
29
52
|
</span>
|
|
30
53
|
</div>
|
|
31
54
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
55
|
+
<span
|
|
56
|
+
className={`inline-flex items-center space-x-1 px-1.5 py-0.5 rounded text-[10px] font-mono border ${STATUS_CLASS[status]}`}
|
|
57
|
+
title={status === 'exited' && exitCode !== null ? `Shell exited with code ${exitCode}` : undefined}
|
|
58
|
+
>
|
|
59
|
+
{status === 'connecting' && <Loader2 size={10} className="animate-spin" />}
|
|
60
|
+
<span>{status === 'exited' && exitCode !== null ? `EXIT ${exitCode}` : STATUS_LABEL[status]}</span>
|
|
61
|
+
</span>
|
|
38
62
|
|
|
39
63
|
<GitRepoDropdown rootPath={rootPath} activeRepo={activeRepo} onSelectRepo={onSelectRepo} />
|
|
64
|
+
|
|
65
|
+
<button
|
|
66
|
+
type="button"
|
|
67
|
+
onClick={onRestart}
|
|
68
|
+
title="Kill this shell and start a new one"
|
|
69
|
+
className="p-1 rounded text-ink/50 hover:text-ink hover:bg-ink/5 transition-colors cursor-pointer flex-shrink-0"
|
|
70
|
+
>
|
|
71
|
+
<RotateCw size={12} />
|
|
72
|
+
</button>
|
|
40
73
|
</div>
|
|
41
74
|
|
|
42
|
-
|
|
43
|
-
<span className="
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
)}
|
|
75
|
+
<span className="hidden sm:flex items-center space-x-2 text-[10px] font-mono text-ink/40 flex-shrink-0 min-w-0">
|
|
76
|
+
{cwd && <span className="truncate max-w-[280px]" title={cwd}>{cwd}</span>}
|
|
77
|
+
{gitBranch && <span>{gitBranch}</span>}
|
|
78
|
+
{shellName && <span>{shellName}</span>}
|
|
79
|
+
</span>
|
|
48
80
|
</div>
|
|
49
81
|
);
|
|
50
82
|
}
|