@civilization/dsh-workspace-files 0.3.0 → 0.3.1

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/src/index.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { exec, spawn } from 'node:child_process'
2
+ import { isAbsolute, resolve } from 'node:path'
1
3
  import type { Context } from '@deepseek-ai/cordis'
2
4
  import Schema from '@deepseek-ai/schemastery'
3
5
  import { scanWorkspaceTree } from './files.js'
@@ -92,6 +94,13 @@ function resolveCwd(ctx: Context, body: Record<string, any>): string {
92
94
 
93
95
  export const SETTINGS_NS = 'workspace-files'
94
96
 
97
+ interface CacheEntry {
98
+ timestamp: number
99
+ result: any
100
+ }
101
+ const scanCache = new Map<string, CacheEntry>()
102
+ const CACHE_TTL_MS = 20_000 // 20 秒热缓存
103
+
95
104
  export function apply(ctx: Context, config: Config = {}): void {
96
105
  const liveConfig = {
97
106
  maxDepth: typeof config?.maxDepth === 'number' && config.maxDepth > 0 ? config.maxDepth : 16,
@@ -147,6 +156,52 @@ export function apply(ctx: Context, config: Config = {}): void {
147
156
  return
148
157
  }
149
158
 
159
+ if (method === 'files.open') {
160
+ try {
161
+ const body = await readJsonBody(req)
162
+ const cwd = resolveCwd(ctx, body)
163
+ const rawPath = String(body.path || '')
164
+ if (!rawPath) {
165
+ writeJson(res, 400, { ok: false, error: { message: 'Missing path parameter' } })
166
+ return
167
+ }
168
+
169
+ const fullPath = isAbsolute(rawPath) ? rawPath : resolve(cwd, rawPath)
170
+ const action = body.action || 'reveal'
171
+ const isDirectory = Boolean(body.isDirectory)
172
+
173
+ if (process.platform === 'win32') {
174
+ const winPath = fullPath.replace(/\//g, '\\')
175
+ if (action === 'reveal') {
176
+ if (isDirectory) {
177
+ spawn('explorer.exe', [winPath], { detached: true, stdio: 'ignore' }).unref()
178
+ } else {
179
+ spawn('explorer.exe', [`/select,${winPath}`], { detached: true, stdio: 'ignore' }).unref()
180
+ }
181
+ } else {
182
+ exec(`start "" "${winPath.replace(/"/g, '\\"')}"`, { windowsHide: true })
183
+ }
184
+ } else if (process.platform === 'darwin') {
185
+ if (action === 'reveal') {
186
+ spawn('open', [isDirectory ? fullPath : '-R', fullPath], { detached: true, stdio: 'ignore' }).unref()
187
+ } else {
188
+ spawn('open', [fullPath], { detached: true, stdio: 'ignore' }).unref()
189
+ }
190
+ } else {
191
+ if (action === 'reveal') {
192
+ spawn('xdg-open', [isDirectory ? fullPath : resolve(fullPath, '..')], { detached: true, stdio: 'ignore' }).unref()
193
+ } else {
194
+ spawn('xdg-open', [fullPath], { detached: true, stdio: 'ignore' }).unref()
195
+ }
196
+ }
197
+
198
+ writeJson(res, 200, { ok: true })
199
+ } catch (err: any) {
200
+ writeJson(res, 500, { ok: false, error: { message: err?.message || String(err) } })
201
+ }
202
+ return
203
+ }
204
+
150
205
  if (method !== 'files.tree') {
151
206
  writeJson(res, 404, { ok: false, error: { message: `Unknown method: ${method}` } })
152
207
  return
@@ -155,11 +210,29 @@ export function apply(ctx: Context, config: Config = {}): void {
155
210
  try {
156
211
  const body = await readJsonBody(req)
157
212
  const cwd = resolveCwd(ctx, body)
213
+ const showHidden = typeof body.showHidden === 'boolean' ? body.showHidden : liveConfig.showHidden
214
+ const showIgnored = Boolean(body.showIgnored)
215
+ const maxDepth = typeof body.maxDepth === 'number' && body.maxDepth > 0 ? body.maxDepth : liveConfig.maxDepth
216
+ const forceRefresh = Boolean(body.forceRefresh)
217
+
218
+ const cacheKey = `${cwd}::${showHidden}::${showIgnored}::${maxDepth}`
219
+ const now = Date.now()
220
+
221
+ if (!forceRefresh) {
222
+ const cached = scanCache.get(cacheKey)
223
+ if (cached && now - cached.timestamp < CACHE_TTL_MS) {
224
+ writeJson(res, 200, { ok: true, value: cached.result, cached: true })
225
+ return
226
+ }
227
+ }
228
+
158
229
  const result = await scanWorkspaceTree(cwd, {
159
- showHidden: typeof body.showHidden === 'boolean' ? body.showHidden : liveConfig.showHidden,
160
- showIgnored: Boolean(body.showIgnored),
161
- maxDepth: typeof body.maxDepth === 'number' && body.maxDepth > 0 ? body.maxDepth : liveConfig.maxDepth,
230
+ showHidden,
231
+ showIgnored,
232
+ maxDepth,
162
233
  })
234
+
235
+ scanCache.set(cacheKey, { timestamp: now, result })
163
236
  writeJson(res, 200, { ok: true, value: result })
164
237
  } catch (err: any) {
165
238
  writeJson(res, 500, { ok: false, error: { message: err?.message || String(err) } })