@civilization/dsh-workspace-files 0.2.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/lib/client.js CHANGED
@@ -247,6 +247,65 @@ window.__ModuleLoader__.load({
247
247
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2 3h4v4H2zM10 9h4v4h-4zM4 7v6h6" })
248
248
  });
249
249
  }
250
+ function IconChevronDown({ size = 14 }) {
251
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
252
+ width: size,
253
+ height: size,
254
+ viewBox: "0 0 16 16",
255
+ fill: "none",
256
+ stroke: "currentColor",
257
+ strokeWidth: "1.5",
258
+ strokeLinecap: "round",
259
+ strokeLinejoin: "round",
260
+ style: {
261
+ display: "inline-block",
262
+ verticalAlign: "middle",
263
+ flexShrink: 0
264
+ },
265
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("polyline", { points: "4 6 8 10 12 6" })
266
+ });
267
+ }
268
+ function IconExplorer({ size = 12 }) {
269
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
270
+ width: size,
271
+ height: size,
272
+ viewBox: "0 0 16 16",
273
+ fill: "currentColor",
274
+ style: {
275
+ display: "inline-block",
276
+ verticalAlign: "middle",
277
+ flexShrink: 0
278
+ },
279
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M1.75 2A1.75 1.75 0 000 3.75v8.5C0 13.216.784 14 1.75 14h12.5A1.75 1.75 0 0016 12.25v-6.5A1.75 1.75 0 0014.25 4H7.5a.25.25 0 01-.2-.1l-.9-1.2C6.07 2.26 5.55 2 5 2H1.75zM1.5 5.5h13v6.75a.25.25 0 01-.25.25H1.75a.25.25 0 01-.25-.25V5.5z" })
280
+ });
281
+ }
282
+ function IconExternalApp({ size = 12 }) {
283
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
284
+ width: size,
285
+ height: size,
286
+ viewBox: "0 0 16 16",
287
+ fill: "none",
288
+ stroke: "currentColor",
289
+ strokeWidth: "1.35",
290
+ strokeLinecap: "round",
291
+ strokeLinejoin: "round",
292
+ style: {
293
+ display: "inline-block",
294
+ verticalAlign: "middle",
295
+ flexShrink: 0
296
+ },
297
+ children: [
298
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M12.5 9.5v3.25a1.25 1.25 0 01-1.25 1.25H3.25A1.25 1.25 0 012 12.75V4.75A1.25 1.25 0 013.25 3.5H6.5" }),
299
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("polyline", { points: "10 2 14 2 14 6" }),
300
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
301
+ x1: "6.5",
302
+ y1: "9.5",
303
+ x2: "13.5",
304
+ y2: "2.5"
305
+ })
306
+ ]
307
+ });
308
+ }
250
309
  //#endregion
251
310
  //#region src/client/index.tsx
252
311
  const inject = ["slots", "sidebarRightTabs"];
@@ -309,6 +368,422 @@ window.__ModuleLoader__.load({
309
368
  key: OFFICIAL_FILES_TAB_ID
310
369
  }, WorkspaceFilesTabTitle)), "dsh-workspace-files: official tab title");
311
370
  }
371
+ const registerSettingsCard = (targetCtx) => {
372
+ if (!targetCtx?.slots) return;
373
+ targetCtx.effect?.(() => targetCtx.slots.inject("settings.plugin.item", function* () {
374
+ yield targetCtx.slots.register({
375
+ name: "settings.plugin.item",
376
+ key: "workspace-files"
377
+ }, WorkspaceFilesSettingsCard);
378
+ yield targetCtx.slots.register({
379
+ name: "settings.plugin.item",
380
+ key: "@civilization/dsh-workspace-files"
381
+ }, WorkspaceFilesSettingsCard);
382
+ }), "dsh-workspace-files: settings card");
383
+ };
384
+ if (slots) registerSettingsCard(ctx);
385
+ if (ctx.inject) ctx.inject(["settingsScope"], (scoped) => {
386
+ registerSettingsCard(scoped);
387
+ });
388
+ }
389
+ const CONFIG_STORAGE_KEY = "dsh_workspace_files_config";
390
+ function loadWorkspaceFilesConfig() {
391
+ try {
392
+ const raw = typeof localStorage !== "undefined" ? localStorage.getItem(CONFIG_STORAGE_KEY) : null;
393
+ if (raw) {
394
+ const parsed = JSON.parse(raw);
395
+ return {
396
+ maxDepth: typeof parsed.maxDepth === "number" && parsed.maxDepth > 0 ? parsed.maxDepth : 16,
397
+ showHidden: Boolean(parsed.showHidden)
398
+ };
399
+ }
400
+ } catch {}
401
+ return {
402
+ maxDepth: 16,
403
+ showHidden: false
404
+ };
405
+ }
406
+ function saveWorkspaceFilesConfig(cfg) {
407
+ try {
408
+ if (typeof localStorage !== "undefined") localStorage.setItem(CONFIG_STORAGE_KEY, JSON.stringify(cfg));
409
+ if (typeof window !== "undefined") window.dispatchEvent(new CustomEvent("dsh-workspace-files:config-change", { detail: cfg }));
410
+ fetch("/dsh-workspace-files/api/config.set", {
411
+ method: "POST",
412
+ headers: { "content-type": "application/json" },
413
+ body: JSON.stringify(cfg)
414
+ }).catch(() => {});
415
+ } catch {}
416
+ }
417
+ function ensureSettingsStyle() {
418
+ if (typeof document === "undefined") return;
419
+ const id = "dsh-workspace-files-settings-style";
420
+ if (document.getElementById(id)) return;
421
+ const style = document.createElement("style");
422
+ style.id = id;
423
+ style.textContent = `
424
+ .dsh-wf-card {
425
+ border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);
426
+ background: var(--dsw-alias-bg-layer-3, #fff);
427
+ border-radius: 12px;
428
+ list-style: none;
429
+ transition: border-color .16s, background .16s;
430
+ box-sizing: border-box;
431
+ }
432
+ .dsh-wf-card-open {
433
+ background: var(--dsw-alias-bg-layer-2, #f7f8fa);
434
+ border-color: var(--dsw-alias-label-dimmed, #c8ccd4);
435
+ }
436
+ .dsh-wf-header {
437
+ -webkit-appearance: none;
438
+ appearance: none;
439
+ width: 100%;
440
+ font: inherit;
441
+ color: inherit;
442
+ text-align: left;
443
+ cursor: pointer;
444
+ background: 0 0;
445
+ border: 0;
446
+ border-radius: 12px;
447
+ align-items: center;
448
+ gap: 12px;
449
+ padding: 14px 16px;
450
+ display: flex;
451
+ }
452
+ .dsh-wf-head-text {
453
+ flex-direction: column;
454
+ flex: 1;
455
+ gap: 4px;
456
+ min-width: 0;
457
+ display: flex;
458
+ }
459
+ .dsh-wf-name {
460
+ color: var(--dsw-alias-label-primary, #1f2328);
461
+ font-size: 15px;
462
+ font-weight: 600;
463
+ line-height: 1.4;
464
+ display: flex;
465
+ align-items: center;
466
+ gap: 8px;
467
+ }
468
+ .dsh-wf-version {
469
+ font-size: 12px;
470
+ font-weight: 400;
471
+ color: var(--dsw-alias-label-tertiary, #8b93a1);
472
+ }
473
+ .dsh-wf-desc {
474
+ color: var(--dsw-alias-label-tertiary, #8b93a1);
475
+ font-size: 13px;
476
+ line-height: 1.5;
477
+ }
478
+ .dsh-wf-chevron {
479
+ color: var(--dsw-alias-label-tertiary, #8b93a1);
480
+ flex: none;
481
+ transition: transform .16s ease-in-out;
482
+ display: inline-flex;
483
+ }
484
+ .dsh-wf-chevron-open {
485
+ transform: rotate(180deg);
486
+ }
487
+ .dsh-wf-body {
488
+ border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb);
489
+ margin: 0 16px;
490
+ padding: 8px 0 12px;
491
+ }
492
+ .dsh-wf-row {
493
+ align-items: center;
494
+ gap: 16px;
495
+ padding: 12px 0;
496
+ display: flex;
497
+ justify-content: space-between;
498
+ }
499
+ .dsh-wf-row + .dsh-wf-row {
500
+ border-top: 1px solid var(--dsw-alias-border-l2, rgba(118, 137, 166, 0.12));
501
+ }
502
+ .dsh-wf-label-box {
503
+ flex-direction: column;
504
+ flex: 1;
505
+ gap: 3px;
506
+ min-width: 0;
507
+ display: flex;
508
+ }
509
+ .dsh-wf-label {
510
+ font-size: 13.5px;
511
+ font-weight: 550;
512
+ color: var(--dsw-alias-label-primary, #1f2328);
513
+ }
514
+ .dsh-wf-hint {
515
+ color: var(--dsw-alias-label-tertiary, #8b93a1);
516
+ font-size: 12px;
517
+ line-height: 18px;
518
+ }
519
+ .dsh-wf-ctrl {
520
+ flex-shrink: 0;
521
+ display: flex;
522
+ align-items: center;
523
+ gap: 8px;
524
+ }
525
+ .dsh-wf-seg {
526
+ border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);
527
+ border-radius: 8px;
528
+ gap: 2px;
529
+ padding: 2px;
530
+ display: inline-flex;
531
+ background: var(--dsw-alias-bg-layer-1, rgba(255, 255, 255, 0.05));
532
+ }
533
+ .dsh-wf-seg-btn {
534
+ font: inherit;
535
+ color: var(--dsw-alias-label-secondary, #6b7280);
536
+ cursor: pointer;
537
+ background: 0 0;
538
+ border: none;
539
+ border-radius: 6px;
540
+ padding: 4px 10px;
541
+ font-size: 12px;
542
+ line-height: 18px;
543
+ transition: all 0.15s;
544
+ }
545
+ .dsh-wf-seg-btn:hover {
546
+ color: var(--dsw-alias-label-primary, #1f2328);
547
+ }
548
+ .dsh-wf-seg-active {
549
+ background: var(--dsw-alias-bg-layer-3, #eef0f4);
550
+ color: var(--dsw-alias-brand-primary, #4f6ef7);
551
+ font-weight: 600;
552
+ box-shadow: 0 1px 2px rgba(0,0,0,0.05);
553
+ }
554
+ .dsh-wf-input {
555
+ box-sizing: border-box;
556
+ border: 1px solid var(--dsw-alias-border-l2, #d1d5db);
557
+ background: var(--dsw-alias-bg-layer-3, #fff);
558
+ width: 64px;
559
+ text-align: center;
560
+ color: var(--dsw-alias-label-primary, #1f2328);
561
+ font: inherit;
562
+ border-radius: 7px;
563
+ padding: 4px 6px;
564
+ font-size: 12.5px;
565
+ line-height: 18px;
566
+ }
567
+ .dsh-wf-input:focus {
568
+ border-color: var(--dsw-alias-brand-primary, #4f6ef7);
569
+ outline: 2px solid color-mix(in srgb, var(--dsw-alias-brand-primary, #4f6ef7) 18%, transparent);
570
+ }
571
+ .dsh-wf-toggle {
572
+ position: relative;
573
+ display: inline-block;
574
+ width: 40px;
575
+ height: 22px;
576
+ cursor: pointer;
577
+ }
578
+ .dsh-wf-toggle input {
579
+ opacity: 0;
580
+ width: 0;
581
+ height: 0;
582
+ position: absolute;
583
+ }
584
+ .dsh-wf-toggle-track {
585
+ position: absolute;
586
+ top: 0; left: 0; right: 0; bottom: 0;
587
+ background-color: var(--dsw-alias-border-l2, #ccc);
588
+ transition: .2s cubic-bezier(.4, 0, .2, 1);
589
+ border-radius: 22px;
590
+ }
591
+ .dsh-wf-toggle input:checked + .dsh-wf-toggle-track {
592
+ background-color: var(--dsw-alias-brand-primary, #4f6ef7);
593
+ }
594
+ .dsh-wf-toggle-thumb {
595
+ position: absolute;
596
+ height: 16px;
597
+ width: 16px;
598
+ left: 3px;
599
+ bottom: 3px;
600
+ background-color: white;
601
+ transition: .2s cubic-bezier(.4, 0, .2, 1);
602
+ border-radius: 50%;
603
+ box-shadow: 0 1px 3px rgba(0,0,0,0.2);
604
+ }
605
+ .dsh-wf-toggle input:checked + .dsh-wf-toggle-track .dsh-wf-toggle-thumb {
606
+ transform: translateX(18px);
607
+ }
608
+ .dsh-wf-footer {
609
+ margin-top: 8px;
610
+ padding-top: 10px;
611
+ border-top: 1px solid var(--dsw-alias-border-l2, rgba(118, 137, 166, 0.12));
612
+ display: flex;
613
+ align-items: center;
614
+ justify-content: space-between;
615
+ }
616
+ .dsh-wf-saved-hint {
617
+ font-size: 11.5px;
618
+ color: var(--dsw-alias-state-success-primary, #10b981);
619
+ display: flex;
620
+ align-items: center;
621
+ gap: 4px;
622
+ }
623
+ .dsh-wf-btn-reset {
624
+ background: transparent;
625
+ border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);
626
+ border-radius: 6px;
627
+ padding: 3px 10px;
628
+ font-size: 12px;
629
+ color: var(--dsw-alias-label-secondary, #6b7280);
630
+ cursor: pointer;
631
+ transition: all 0.15s;
632
+ }
633
+ .dsh-wf-btn-reset:hover {
634
+ background: var(--dsw-alias-bg-layer-2, rgba(255,255,255,0.08));
635
+ color: var(--dsw-alias-label-primary, #1f2328);
636
+ }
637
+ `;
638
+ document.head.appendChild(style);
639
+ }
640
+ function WorkspaceFilesSettingsCard() {
641
+ const [open, setOpen] = (0, react.useState)(false);
642
+ const [config, setConfig] = (0, react.useState)(() => loadWorkspaceFilesConfig());
643
+ const [savedTick, setSavedTick] = (0, react.useState)(false);
644
+ (0, react.useEffect)(() => {
645
+ ensureSettingsStyle();
646
+ }, []);
647
+ const updateConfig = (patch) => {
648
+ const next = {
649
+ ...config,
650
+ ...patch
651
+ };
652
+ setConfig(next);
653
+ saveWorkspaceFilesConfig(next);
654
+ setSavedTick(true);
655
+ setTimeout(() => setSavedTick(false), 2e3);
656
+ };
657
+ const handleDepthSelect = (depth) => {
658
+ updateConfig({ maxDepth: depth });
659
+ };
660
+ const handleDepthInput = (e) => {
661
+ const val = parseInt(e.target.value, 10);
662
+ if (!isNaN(val) && val >= 1 && val <= 100) updateConfig({ maxDepth: val });
663
+ };
664
+ const handleToggleHidden = () => {
665
+ updateConfig({ showHidden: !config.showHidden });
666
+ };
667
+ const handleReset = () => {
668
+ const def = {
669
+ maxDepth: 16,
670
+ showHidden: false
671
+ };
672
+ setConfig(def);
673
+ saveWorkspaceFilesConfig(def);
674
+ setSavedTick(true);
675
+ setTimeout(() => setSavedTick(false), 2e3);
676
+ };
677
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
678
+ className: open ? "dsh-wf-card dsh-wf-card-open" : "dsh-wf-card",
679
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
680
+ type: "button",
681
+ className: "dsh-wf-header",
682
+ "aria-expanded": open,
683
+ onClick: () => setOpen(!open),
684
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
685
+ className: "dsh-wf-head-text",
686
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
687
+ className: "dsh-wf-name",
688
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "工作区文件" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
689
+ className: "dsh-wf-version",
690
+ children: "v0.3.0"
691
+ })]
692
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
693
+ className: "dsh-wf-desc",
694
+ children: "浏览与检索工作区文件树,支持递归目录扫描与一键引用。"
695
+ })]
696
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
697
+ className: open ? "dsh-wf-chevron dsh-wf-chevron-open" : "dsh-wf-chevron",
698
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconChevronDown, { size: 14 })
699
+ })]
700
+ }), open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
701
+ className: "dsh-wf-body",
702
+ children: [
703
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
704
+ className: "dsh-wf-row",
705
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
706
+ className: "dsh-wf-label-box",
707
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
708
+ className: "dsh-wf-label",
709
+ children: "目录扫描最大深度"
710
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
711
+ className: "dsh-wf-hint",
712
+ children: "工作区递归扫描的最大目录层级(默认 16,范围 1~100)。若工程目录较深可适当调大。"
713
+ })]
714
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
715
+ className: "dsh-wf-ctrl",
716
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
717
+ className: "dsh-wf-seg",
718
+ children: [
719
+ 8,
720
+ 16,
721
+ 32,
722
+ 64
723
+ ].map((d) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
724
+ type: "button",
725
+ className: config.maxDepth === d ? "dsh-wf-seg-btn dsh-wf-seg-active" : "dsh-wf-seg-btn",
726
+ onClick: () => handleDepthSelect(d),
727
+ children: d
728
+ }, d))
729
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
730
+ type: "number",
731
+ min: "1",
732
+ max: "100",
733
+ className: "dsh-wf-input",
734
+ value: config.maxDepth,
735
+ onChange: handleDepthInput,
736
+ title: "自定义深度 (1-100)"
737
+ })]
738
+ })]
739
+ }),
740
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
741
+ className: "dsh-wf-row",
742
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
743
+ className: "dsh-wf-label-box",
744
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
745
+ className: "dsh-wf-label",
746
+ children: "默认显示隐藏文件"
747
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
748
+ className: "dsh-wf-hint",
749
+ children: "打开文件树时是否默认展示以点开头的隐藏文件或文件夹(如 .gitignore, .env 等)。"
750
+ })]
751
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
752
+ className: "dsh-wf-ctrl",
753
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
754
+ className: "dsh-wf-toggle",
755
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
756
+ type: "checkbox",
757
+ checked: config.showHidden,
758
+ onChange: handleToggleHidden
759
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
760
+ className: "dsh-wf-toggle-track",
761
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "dsh-wf-toggle-thumb" })
762
+ })]
763
+ })
764
+ })]
765
+ }),
766
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
767
+ className: "dsh-wf-footer",
768
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: savedTick ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
769
+ className: "dsh-wf-saved-hint",
770
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconCheck, { size: 12 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "已保存设置" })]
771
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
772
+ style: {
773
+ fontSize: 11,
774
+ color: "var(--dsw-alias-label-tertiary, #8b93a1)"
775
+ },
776
+ children: "设置改动即时生效并同步至工作区文件树"
777
+ }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
778
+ type: "button",
779
+ className: "dsh-wf-btn-reset",
780
+ onClick: handleReset,
781
+ children: "恢复默认"
782
+ })]
783
+ })
784
+ ]
785
+ })]
786
+ });
312
787
  }
313
788
  function WorkspaceFilesView({ sessionId, cwd, onOpenFile }) {
314
789
  const [data, setData] = (0, react.useState)(null);
@@ -317,21 +792,34 @@ window.__ModuleLoader__.load({
317
792
  const [query, setQuery] = (0, react.useState)("");
318
793
  const [toast, setToast] = (0, react.useState)(null);
319
794
  const [expandedPaths, setExpandedPaths] = (0, react.useState)(() => /* @__PURE__ */ new Set());
320
- const [showHidden, setShowHidden] = (0, react.useState)(false);
795
+ const [activeConfig, setActiveConfig] = (0, react.useState)(() => loadWorkspaceFilesConfig());
796
+ const [showHidden, setShowHidden] = (0, react.useState)(() => loadWorkspaceFilesConfig().showHidden);
321
797
  const toastTimer = (0, react.useRef)(null);
322
798
  const showToastMsg = (0, react.useCallback)((msg) => {
323
799
  setToast(msg);
324
800
  if (toastTimer.current) window.clearTimeout(toastTimer.current);
325
801
  toastTimer.current = window.setTimeout(() => setToast(null), 2e3);
326
802
  }, []);
327
- const loadTree = (0, react.useCallback)(async (quiet = false) => {
803
+ (0, react.useEffect)(() => {
804
+ const handleCfgChange = (e) => {
805
+ if (e.detail) {
806
+ setActiveConfig(e.detail);
807
+ setShowHidden(Boolean(e.detail.showHidden));
808
+ }
809
+ };
810
+ window.addEventListener("dsh-workspace-files:config-change", handleCfgChange);
811
+ return () => window.removeEventListener("dsh-workspace-files:config-change", handleCfgChange);
812
+ }, []);
813
+ const loadTree = (0, react.useCallback)(async (quiet = false, forceRefresh = false) => {
328
814
  if (!quiet) setLoading(true);
329
815
  setError(null);
330
816
  try {
331
817
  const res = await call("files.tree", {
332
818
  sessionId,
333
819
  cwd,
334
- showHidden
820
+ showHidden,
821
+ maxDepth: activeConfig.maxDepth,
822
+ forceRefresh
335
823
  });
336
824
  setData(res);
337
825
  setExpandedPaths((prev) => {
@@ -348,7 +836,8 @@ window.__ModuleLoader__.load({
348
836
  }, [
349
837
  sessionId,
350
838
  cwd,
351
- showHidden
839
+ showHidden,
840
+ activeConfig.maxDepth
352
841
  ]);
353
842
  (0, react.useEffect)(() => {
354
843
  loadTree();
@@ -438,6 +927,44 @@ window.__ModuleLoader__.load({
438
927
  else showToastMsg(`已复制引用: ${mentionText.trim()}`);
439
928
  });
440
929
  };
930
+ const handleRevealInExplorer = (e, item) => {
931
+ e.stopPropagation();
932
+ fetch("/dsh-workspace-files/api/files.open", {
933
+ method: "POST",
934
+ headers: { "content-type": "application/json" },
935
+ body: JSON.stringify({
936
+ action: "reveal",
937
+ path: item.path,
938
+ isDirectory: Boolean(item.isDirectory),
939
+ sessionId,
940
+ cwd
941
+ })
942
+ }).then((res) => res.json()).then((data) => {
943
+ if (data.ok) showToastMsg(`已在资源管理器中显示: ${item.name}`);
944
+ else showToastMsg(`打开失败: ${data.error?.message || "未知错误"}`);
945
+ }).catch((err) => {
946
+ showToastMsg(`请求失败: ${err?.message || String(err)}`);
947
+ });
948
+ };
949
+ const handleOpenDefaultApp = (e, item) => {
950
+ e.stopPropagation();
951
+ fetch("/dsh-workspace-files/api/files.open", {
952
+ method: "POST",
953
+ headers: { "content-type": "application/json" },
954
+ body: JSON.stringify({
955
+ action: "openDefault",
956
+ path: item.path,
957
+ isDirectory: Boolean(item.isDirectory),
958
+ sessionId,
959
+ cwd
960
+ })
961
+ }).then((res) => res.json()).then((data) => {
962
+ if (data.ok) showToastMsg(`已启动系统应用打开: ${item.name}`);
963
+ else showToastMsg(`打开失败: ${data.error?.message || "未知错误"}`);
964
+ }).catch((err) => {
965
+ showToastMsg(`请求失败: ${err?.message || String(err)}`);
966
+ });
967
+ };
441
968
  const [searchViewMode, setSearchViewMode] = (0, react.useState)("flat");
442
969
  const [searchExpandedPaths, setSearchExpandedPaths] = (0, react.useState)(() => /* @__PURE__ */ new Set());
443
970
  const { filteredTreeItems, flatSearchResults } = (0, react.useMemo)(() => {
@@ -597,7 +1124,7 @@ window.__ModuleLoader__.load({
597
1124
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
598
1125
  type: "button",
599
1126
  className: "dsh-files-tool-btn",
600
- onClick: () => void loadTree(true),
1127
+ onClick: () => void loadTree(false, true),
601
1128
  disabled: loading,
602
1129
  title: "刷新文件树",
603
1130
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconRefresh, { size: 13 })
@@ -660,7 +1187,8 @@ window.__ModuleLoader__.load({
660
1187
  children: [
661
1188
  "找到 ",
662
1189
  flatSearchResults.length,
663
- " 个匹配项"
1190
+ " 个匹配项",
1191
+ flatSearchResults.length > 150 ? "(展示前 150 项)" : ""
664
1192
  ]
665
1193
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
666
1194
  type: "button",
@@ -669,9 +1197,9 @@ window.__ModuleLoader__.load({
669
1197
  title: "切换为可折叠的树形视图",
670
1198
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconTree, { size: 12 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "切为树形" })]
671
1199
  })]
672
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1200
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
673
1201
  className: "dsh-files-flat-list",
674
- children: flatSearchResults.map(({ item, parentDir }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1202
+ children: [flatSearchResults.slice(0, 150).map(({ item, parentDir }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
675
1203
  className: `dsh-files-flat-row ${item.isDirectory ? "is-directory" : ""}`,
676
1204
  onClick: () => {
677
1205
  if (item.isDirectory) handleJumpToFolderInTree(item.path);
@@ -715,25 +1243,51 @@ window.__ModuleLoader__.load({
715
1243
  }),
716
1244
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
717
1245
  className: "dsh-files-row-actions",
718
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
719
- type: "button",
720
- className: "dsh-files-action-btn dsh-files-action-at",
721
- onClick: (e) => handleMention(e, item),
722
- title: `一键 @ 引用此${item.isDirectory ? "目录" : "文件"}到当前会话`,
723
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAt, { size: 13 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
724
- className: "dsh-files-action-at-text",
725
- children: "@引用"
726
- })]
727
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
728
- type: "button",
729
- className: "dsh-files-action-btn",
730
- onClick: (e) => handleCopyPath(e, item.path),
731
- title: "复制相对路径",
732
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconCopy, { size: 12 })
733
- })]
1246
+ children: [
1247
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1248
+ type: "button",
1249
+ className: "dsh-files-action-btn dsh-files-action-at",
1250
+ onClick: (e) => handleMention(e, item),
1251
+ title: `一键 @ 引用此${item.isDirectory ? "目录" : "文件"}到当前会话`,
1252
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAt, { size: 13 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1253
+ className: "dsh-files-action-at-text",
1254
+ children: "@引用"
1255
+ })]
1256
+ }),
1257
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1258
+ type: "button",
1259
+ className: "dsh-files-action-btn",
1260
+ onClick: (e) => handleRevealInExplorer(e, item),
1261
+ title: `在文件资源管理器中显示此${item.isDirectory ? "目录" : "文件"}`,
1262
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconExplorer, { size: 12 })
1263
+ }),
1264
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1265
+ type: "button",
1266
+ className: "dsh-files-action-btn",
1267
+ onClick: (e) => handleOpenDefaultApp(e, item),
1268
+ title: `用系统默认应用打开此${item.isDirectory ? "目录" : "文件"}`,
1269
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconExternalApp, { size: 12 })
1270
+ }),
1271
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1272
+ type: "button",
1273
+ className: "dsh-files-action-btn",
1274
+ onClick: (e) => handleCopyPath(e, item.path),
1275
+ title: "复制相对路径",
1276
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconCopy, { size: 12 })
1277
+ })
1278
+ ]
734
1279
  })
735
1280
  ]
736
- }, item.path))
1281
+ }, item.path)), flatSearchResults.length > 150 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1282
+ style: {
1283
+ padding: "10px 14px",
1284
+ fontSize: 11,
1285
+ textAlign: "center",
1286
+ color: "var(--dsw-alias-label-tertiary, #8b93a1)",
1287
+ borderTop: "1px dashed var(--dsw-alias-border-l2, #e5e7eb)"
1288
+ },
1289
+ children: "匹配项较多,已限制展示前 150 项以保证流畅度,请输入更详细关键字"
1290
+ })]
737
1291
  })]
738
1292
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
739
1293
  className: "dsh-files-tree",
@@ -766,7 +1320,9 @@ window.__ModuleLoader__.load({
766
1320
  },
767
1321
  onOpenFile,
768
1322
  onMention: handleMention,
769
- onCopyPath: handleCopyPath
1323
+ onCopyPath: handleCopyPath,
1324
+ onRevealInExplorer: handleRevealInExplorer,
1325
+ onOpenDefaultApp: handleOpenDefaultApp
770
1326
  }, item.path))]
771
1327
  })
772
1328
  }),
@@ -778,7 +1334,7 @@ window.__ModuleLoader__.load({
778
1334
  });
779
1335
  }
780
1336
  function FileTreeNode(props) {
781
- const { item, depth, query, isSearchMode, expandedPaths, onToggleExpand, onOpenFile, onMention, onCopyPath } = props;
1337
+ const { item, depth, query, isSearchMode, expandedPaths, onToggleExpand, onOpenFile, onMention, onCopyPath, onRevealInExplorer, onOpenDefaultApp } = props;
782
1338
  const isExpanded = expandedPaths.has(item.path);
783
1339
  if (item.isDirectory) {
784
1340
  const childCount = item.children?.length ?? 0;
@@ -816,22 +1372,39 @@ window.__ModuleLoader__.load({
816
1372
  }),
817
1373
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
818
1374
  className: "dsh-files-row-actions",
819
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
820
- type: "button",
821
- className: "dsh-files-action-btn dsh-files-action-at",
822
- onClick: (e) => onMention(e, item),
823
- title: "一键 @ 引用此目录到当前会话",
824
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAt, { size: 13 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
825
- className: "dsh-files-action-at-text",
826
- children: "@引用"
827
- })]
828
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
829
- type: "button",
830
- className: "dsh-files-action-btn",
831
- onClick: (e) => onCopyPath(e, item.path),
832
- title: "复制目录路径",
833
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconCopy, { size: 12 })
834
- })]
1375
+ children: [
1376
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1377
+ type: "button",
1378
+ className: "dsh-files-action-btn dsh-files-action-at",
1379
+ onClick: (e) => onMention(e, item),
1380
+ title: "一键 @ 引用此目录到当前会话",
1381
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAt, { size: 13 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1382
+ className: "dsh-files-action-at-text",
1383
+ children: "@引用"
1384
+ })]
1385
+ }),
1386
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1387
+ type: "button",
1388
+ className: "dsh-files-action-btn",
1389
+ onClick: (e) => onRevealInExplorer(e, item),
1390
+ title: "在文件资源管理器中打开此目录",
1391
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconExplorer, { size: 12 })
1392
+ }),
1393
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1394
+ type: "button",
1395
+ className: "dsh-files-action-btn",
1396
+ onClick: (e) => onOpenDefaultApp(e, item),
1397
+ title: "用系统默认应用打开此目录",
1398
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconExternalApp, { size: 12 })
1399
+ }),
1400
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1401
+ type: "button",
1402
+ className: "dsh-files-action-btn",
1403
+ onClick: (e) => onCopyPath(e, item.path),
1404
+ title: "复制目录路径",
1405
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconCopy, { size: 12 })
1406
+ })
1407
+ ]
835
1408
  })
836
1409
  ]
837
1410
  }), isExpanded && item.children && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -845,7 +1418,9 @@ window.__ModuleLoader__.load({
845
1418
  onToggleExpand,
846
1419
  onOpenFile,
847
1420
  onMention,
848
- onCopyPath
1421
+ onCopyPath,
1422
+ onRevealInExplorer,
1423
+ onOpenDefaultApp
849
1424
  }, child.path))
850
1425
  })]
851
1426
  });
@@ -875,22 +1450,39 @@ window.__ModuleLoader__.load({
875
1450
  }),
876
1451
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
877
1452
  className: "dsh-files-row-actions",
878
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
879
- type: "button",
880
- className: "dsh-files-action-btn dsh-files-action-at",
881
- onClick: (e) => onMention(e, item),
882
- title: "一键 @ 引用此文件到当前会话",
883
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAt, { size: 13 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
884
- className: "dsh-files-action-at-text",
885
- children: "@引用"
886
- })]
887
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
888
- type: "button",
889
- className: "dsh-files-action-btn",
890
- onClick: (e) => onCopyPath(e, item.path),
891
- title: "复制相对路径",
892
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconCopy, { size: 12 })
893
- })]
1453
+ children: [
1454
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1455
+ type: "button",
1456
+ className: "dsh-files-action-btn dsh-files-action-at",
1457
+ onClick: (e) => onMention(e, item),
1458
+ title: "一键 @ 引用此文件到当前会话",
1459
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAt, { size: 13 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1460
+ className: "dsh-files-action-at-text",
1461
+ children: "@引用"
1462
+ })]
1463
+ }),
1464
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1465
+ type: "button",
1466
+ className: "dsh-files-action-btn",
1467
+ onClick: (e) => onRevealInExplorer(e, item),
1468
+ title: "在文件资源管理器中显示此文件",
1469
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconExplorer, { size: 12 })
1470
+ }),
1471
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1472
+ type: "button",
1473
+ className: "dsh-files-action-btn",
1474
+ onClick: (e) => onOpenDefaultApp(e, item),
1475
+ title: "用系统默认应用打开此文件",
1476
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconExternalApp, { size: 12 })
1477
+ }),
1478
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1479
+ type: "button",
1480
+ className: "dsh-files-action-btn",
1481
+ onClick: (e) => onCopyPath(e, item.path),
1482
+ title: "复制相对路径",
1483
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconCopy, { size: 12 })
1484
+ })
1485
+ ]
894
1486
  })
895
1487
  ]
896
1488
  });
@@ -1624,8 +2216,11 @@ window.__ModuleLoader__.load({
1624
2216
  ` });
1625
2217
  }
1626
2218
  //#endregion
2219
+ exports.WorkspaceFilesSettingsCard = WorkspaceFilesSettingsCard;
1627
2220
  exports.apply = apply;
1628
2221
  exports.inject = inject;
2222
+ exports.loadWorkspaceFilesConfig = loadWorkspaceFilesConfig;
2223
+ exports.saveWorkspaceFilesConfig = saveWorkspaceFilesConfig;
1629
2224
  return module.exports;
1630
2225
  }
1631
2226
  });