dsh-explorer 0.0.0-stage → 0.1.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/LICENSE +22 -0
- package/README.md +106 -2
- package/cordis.patch.yml +5 -0
- package/icon.svg +7 -0
- package/lib/client.js +2814 -0
- package/lib/index.js +747 -0
- package/package.json +92 -4
- package/src/client/ExplorerContextMenu.tsx +159 -0
- package/src/client/ExplorerHeader.tsx +75 -0
- package/src/client/ExplorerOptionsModal.tsx +243 -0
- package/src/client/ExplorerRow.tsx +240 -0
- package/src/client/ExplorerSearch.tsx +42 -0
- package/src/client/ExplorerView.tsx +1139 -0
- package/src/client/api.ts +121 -0
- package/src/client/conversation-draft.ts +635 -0
- package/src/client/css-modules.d.ts +5 -0
- package/src/client/drag-drop.ts +209 -0
- package/src/client/explorer.module.css +628 -0
- package/src/client/index.tsx +160 -0
- package/src/client/options.ts +59 -0
- package/src/client/vscode-theme.tsx +250 -0
- package/src/config.ts +11 -0
- package/src/fs-operations.ts +116 -0
- package/src/fs-tree.ts +155 -0
- package/src/fs-watch.ts +179 -0
- package/src/git-status.ts +161 -0
- package/src/index.ts +165 -0
- package/src/path-security.ts +22 -0
- package/src/session-path.ts +35 -0
- package/src/wire.ts +63 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { homedir } from 'node:os'
|
|
2
|
+
import type { Context } from './index.ts'
|
|
3
|
+
|
|
4
|
+
export function resolveSessionCwd(ctx: Context, sessionId?: string): string {
|
|
5
|
+
try {
|
|
6
|
+
const sessionService = (ctx.get('sessions') ?? (ctx as any).sessions) as unknown as {
|
|
7
|
+
get?: (id: string) => { cwd?: string; workingDirectory?: string; header?: { cwd?: string } } | undefined
|
|
8
|
+
list?: () => Array<{ cwd?: string; workingDirectory?: string; header?: { cwd?: string } }>
|
|
9
|
+
} | undefined
|
|
10
|
+
|
|
11
|
+
if (sessionService) {
|
|
12
|
+
if (sessionId) {
|
|
13
|
+
const direct = sessionService.get?.(sessionId)
|
|
14
|
+
if (direct?.header?.cwd) return direct.header.cwd
|
|
15
|
+
if (direct?.cwd) return direct.cwd
|
|
16
|
+
if (direct?.workingDirectory) return direct.workingDirectory
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// If no sessionId or direct session not found, pick the latest session
|
|
20
|
+
if (typeof sessionService.list === 'function') {
|
|
21
|
+
const all = sessionService.list()
|
|
22
|
+
for (let i = all.length - 1; i >= 0; i--) {
|
|
23
|
+
const s = all[i]
|
|
24
|
+
if (s?.header?.cwd) return s.header.cwd
|
|
25
|
+
if (s?.cwd) return s.cwd
|
|
26
|
+
if (s?.workingDirectory) return s.workingDirectory
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
} catch {
|
|
31
|
+
// Ignore and fallback
|
|
32
|
+
}
|
|
33
|
+
return homedir()
|
|
34
|
+
}
|
|
35
|
+
|
package/src/wire.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http'
|
|
2
|
+
|
|
3
|
+
export class ExplorerError extends Error {
|
|
4
|
+
readonly code: string
|
|
5
|
+
readonly status: number
|
|
6
|
+
|
|
7
|
+
constructor(code: string, message: string, status: number = 400) {
|
|
8
|
+
super(message)
|
|
9
|
+
this.name = 'ExplorerError'
|
|
10
|
+
this.code = code
|
|
11
|
+
this.status = status
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function writeJson(res: ServerResponse, data: unknown, status = 200): void {
|
|
16
|
+
const payload = JSON.stringify(data)
|
|
17
|
+
res.writeHead(status, {
|
|
18
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
19
|
+
'Content-Length': Buffer.byteLength(payload),
|
|
20
|
+
'Cache-Control': 'no-store',
|
|
21
|
+
})
|
|
22
|
+
res.end(payload)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function writeOk(res: ServerResponse, data: Record<string, unknown> = {}): void {
|
|
26
|
+
writeJson(res, { ok: true, ...data })
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function writeError(res: ServerResponse, error: unknown): void {
|
|
30
|
+
if (error instanceof ExplorerError) {
|
|
31
|
+
writeJson(res, { ok: false, code: error.code, message: error.message }, error.status)
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
35
|
+
writeJson(res, { ok: false, code: 'internal-error', message }, 500)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function readJsonBody<T = unknown>(req: IncomingMessage, limitBytes = 10 * 1024 * 1024): Promise<T> {
|
|
39
|
+
const text = await readTextBody(req, limitBytes)
|
|
40
|
+
if (!text.trim()) {
|
|
41
|
+
throw new ExplorerError('bad-request', 'empty request body', 400)
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
return JSON.parse(text) as T
|
|
45
|
+
} catch {
|
|
46
|
+
throw new ExplorerError('bad-request', 'invalid json body', 400)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function readTextBody(req: IncomingMessage, limitBytes = 10 * 1024 * 1024): Promise<string> {
|
|
51
|
+
let size = 0
|
|
52
|
+
const chunks: Buffer[] = []
|
|
53
|
+
for await (const chunk of req) {
|
|
54
|
+
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)
|
|
55
|
+
size += buf.length
|
|
56
|
+
if (size > limitBytes) {
|
|
57
|
+
throw new ExplorerError('payload-too-large', `request body exceeded ${limitBytes} bytes`, 413)
|
|
58
|
+
}
|
|
59
|
+
chunks.push(buf)
|
|
60
|
+
}
|
|
61
|
+
return Buffer.concat(chunks).toString('utf-8')
|
|
62
|
+
}
|
|
63
|
+
|