fix(workspace): docs discovery for doc/ dirs + SSH terminal tab args
- Add doc/ alongside docs/ in markdown file discovery (groups.rs) - Add SETUP.md to priority root files - Fix SSH terminal tabs: resolve session args via sshArgsCache derived from listSshSessions() instead of passing empty args - Fix Agent Preview: only mount xterm when tab is active (prevents CanvasAddon crash on hidden elements) - Separate tab type rendering (shell/ssh/agent-preview) with proper guards
This commit is contained in:
parent
dc0ffb6dbf
commit
44610f3177
2 changed files with 69 additions and 19 deletions
|
|
@ -83,7 +83,7 @@ pub fn discover_markdown_files(cwd: &str) -> Result<Vec<MdFileEntry>, String> {
|
||||||
let mut entries = Vec::new();
|
let mut entries = Vec::new();
|
||||||
|
|
||||||
// Priority files at root
|
// Priority files at root
|
||||||
for name in &["CLAUDE.md", "README.md", "CHANGELOG.md", "TODO.md"] {
|
for name in &["CLAUDE.md", "README.md", "CHANGELOG.md", "TODO.md", "SETUP.md"] {
|
||||||
let path = root.join(name);
|
let path = root.join(name);
|
||||||
if path.is_file() {
|
if path.is_file() {
|
||||||
entries.push(MdFileEntry {
|
entries.push(MdFileEntry {
|
||||||
|
|
@ -94,11 +94,13 @@ pub fn discover_markdown_files(cwd: &str) -> Result<Vec<MdFileEntry>, String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// docs/ directory (max 20 entries, depth 2)
|
// docs/ or doc/ directory (max 20 entries, depth 2)
|
||||||
let docs_dir = root.join("docs");
|
for dir_name in &["docs", "doc"] {
|
||||||
|
let docs_dir = root.join(dir_name);
|
||||||
if docs_dir.is_dir() {
|
if docs_dir.is_dir() {
|
||||||
scan_md_dir(&docs_dir, &mut entries, 2, 20);
|
scan_md_dir(&docs_dir, &mut entries, 2, 20);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(entries)
|
Ok(entries)
|
||||||
}
|
}
|
||||||
|
|
@ -222,4 +224,26 @@ mod tests {
|
||||||
assert_eq!(result.len(), 2);
|
assert_eq!(result.len(), 2);
|
||||||
assert!(result.iter().all(|e| !e.priority));
|
assert!(result.iter().all(|e| !e.priority));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_discover_finds_doc_dir() {
|
||||||
|
let dir = tempfile::tempdir().unwrap();
|
||||||
|
let doc = dir.path().join("doc");
|
||||||
|
std::fs::create_dir(&doc).unwrap();
|
||||||
|
std::fs::write(doc.join("requirements.md"), "# Req").unwrap();
|
||||||
|
let result = discover_markdown_files(dir.path().to_str().unwrap()).unwrap();
|
||||||
|
assert_eq!(result.len(), 1);
|
||||||
|
assert_eq!(result[0].name, "requirements.md");
|
||||||
|
assert!(!result[0].priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_discover_finds_setup_md() {
|
||||||
|
let dir = tempfile::tempdir().unwrap();
|
||||||
|
std::fs::write(dir.path().join("SETUP.md"), "# Setup").unwrap();
|
||||||
|
let result = discover_markdown_files(dir.path().to_str().unwrap()).unwrap();
|
||||||
|
assert_eq!(result.len(), 1);
|
||||||
|
assert_eq!(result[0].name, "SETUP.md");
|
||||||
|
assert!(result[0].priority);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { onMount } from 'svelte';
|
||||||
import type { ProjectConfig } from '../../types/groups';
|
import type { ProjectConfig } from '../../types/groups';
|
||||||
import {
|
import {
|
||||||
getTerminalTabs,
|
getTerminalTabs,
|
||||||
|
|
@ -6,9 +7,33 @@
|
||||||
removeTerminalTab,
|
removeTerminalTab,
|
||||||
type TerminalTab,
|
type TerminalTab,
|
||||||
} from '../../stores/workspace.svelte';
|
} from '../../stores/workspace.svelte';
|
||||||
|
import { listSshSessions, type SshSession } from '../../adapters/ssh-bridge';
|
||||||
import TerminalPane from '../Terminal/TerminalPane.svelte';
|
import TerminalPane from '../Terminal/TerminalPane.svelte';
|
||||||
import AgentPreviewPane from '../Terminal/AgentPreviewPane.svelte';
|
import AgentPreviewPane from '../Terminal/AgentPreviewPane.svelte';
|
||||||
|
|
||||||
|
/** Cached SSH sessions for building args */
|
||||||
|
let sshSessions = $state<SshSession[]>([]);
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
listSshSessions().then(s => { sshSessions = s; }).catch(() => {});
|
||||||
|
});
|
||||||
|
|
||||||
|
/** Resolved SSH args per tab, keyed by tab id */
|
||||||
|
let sshArgsCache = $derived.by(() => {
|
||||||
|
const cache: Record<string, string[]> = {};
|
||||||
|
for (const tab of tabs) {
|
||||||
|
if (tab.type !== 'ssh' || !tab.sshSessionId) continue;
|
||||||
|
const session = sshSessions.find(s => s.id === tab.sshSessionId);
|
||||||
|
if (!session) continue;
|
||||||
|
const args: string[] = [];
|
||||||
|
if (session.key_file) args.push('-i', session.key_file);
|
||||||
|
if (session.port && session.port !== 22) args.push('-p', String(session.port));
|
||||||
|
args.push(`${session.username}@${session.host}`);
|
||||||
|
cache[tab.id] = args;
|
||||||
|
}
|
||||||
|
return cache;
|
||||||
|
});
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
project: ProjectConfig;
|
project: ProjectConfig;
|
||||||
agentSessionId?: string | null;
|
agentSessionId?: string | null;
|
||||||
|
|
@ -100,17 +125,23 @@
|
||||||
|
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
{#each tabs as tab (tab.id)}
|
{#each tabs as tab (tab.id)}
|
||||||
<div class="tab-pane" class:visible={activeTabId === tab.id}>
|
<div class="tab-pane" style:display={activeTabId === tab.id ? 'block' : 'none'}>
|
||||||
{#if activeTabId === tab.id}
|
|
||||||
{#if tab.type === 'agent-preview' && tab.agentSessionId}
|
{#if tab.type === 'agent-preview' && tab.agentSessionId}
|
||||||
|
{#if activeTabId === tab.id}
|
||||||
<AgentPreviewPane sessionId={tab.agentSessionId} />
|
<AgentPreviewPane sessionId={tab.agentSessionId} />
|
||||||
{:else}
|
{/if}
|
||||||
|
{:else if tab.type === 'ssh' && sshArgsCache[tab.id]}
|
||||||
|
<TerminalPane
|
||||||
|
cwd={project.cwd}
|
||||||
|
shell="/usr/bin/ssh"
|
||||||
|
args={sshArgsCache[tab.id]}
|
||||||
|
onExit={() => handleTabExit(tab.id)}
|
||||||
|
/>
|
||||||
|
{:else if tab.type === 'shell'}
|
||||||
<TerminalPane
|
<TerminalPane
|
||||||
cwd={project.cwd}
|
cwd={project.cwd}
|
||||||
shell={tab.type === 'ssh' ? '/usr/bin/ssh' : undefined}
|
|
||||||
onExit={() => handleTabExit(tab.id)}
|
onExit={() => handleTabExit(tab.id)}
|
||||||
/>
|
/>
|
||||||
{/if}
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
@ -217,11 +248,6 @@
|
||||||
.tab-pane {
|
.tab-pane {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-pane.visible {
|
|
||||||
display: block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-terminals {
|
.empty-terminals {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue