@qodalis/cli-files 2.0.0-beta.12 → 2.0.0-beta.14

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.
@@ -628,14 +628,14 @@ var files = (() => {
628
628
  var require_sort = __commonJS({
629
629
  "../../node_modules/.pnpm/semver@7.7.4/node_modules/semver/functions/sort.js"(exports$1, module2) {
630
630
  var compareBuild = require_compare_build();
631
- var sort = (list, loose) => list.sort((a, b) => compareBuild(a, b, loose));
631
+ var sort = (list2, loose) => list2.sort((a, b) => compareBuild(a, b, loose));
632
632
  module2.exports = sort;
633
633
  }
634
634
  });
635
635
  var require_rsort = __commonJS({
636
636
  "../../node_modules/.pnpm/semver@7.7.4/node_modules/semver/functions/rsort.js"(exports$1, module2) {
637
637
  var compareBuild = require_compare_build();
638
- var rsort = (list, loose) => list.sort((a, b) => compareBuild(b, a, loose));
638
+ var rsort = (list2, loose) => list2.sort((a, b) => compareBuild(b, a, loose));
639
639
  module2.exports = rsort;
640
640
  }
641
641
  });
@@ -1834,6 +1834,21 @@ var files = (() => {
1834
1834
  return CliForegroundColor2;
1835
1835
  })(CliForegroundColor || {});
1836
1836
  var ICliCompletionProvider_TOKEN = "cli-completion-provider";
1837
+ function resolveHeaders(provider) {
1838
+ if (!provider) return {};
1839
+ return typeof provider === "function" ? provider() : provider;
1840
+ }
1841
+ var CliAccessDeniedError = class _CliAccessDeniedError extends Error {
1842
+ constructor(message = "permission denied") {
1843
+ super(message);
1844
+ this.code = "EACCES";
1845
+ this.name = "CliAccessDeniedError";
1846
+ Object.setPrototypeOf(this, _CliAccessDeniedError.prototype);
1847
+ }
1848
+ };
1849
+ function isCliAccessDeniedError(error) {
1850
+ return error instanceof CliAccessDeniedError || !!error && typeof error === "object" && error.name === "CliAccessDeniedError";
1851
+ }
1837
1852
  var DefaultLibraryAuthor = {
1838
1853
  name: "Nicolae Lupei",
1839
1854
  email: "nicolae.lupei@qodalis.com"
@@ -1860,9 +1875,12 @@ var files = (() => {
1860
1875
  * Returns the negotiated API version and the base path for all subsequent calls,
1861
1876
  * or null if the server is unreachable or incompatible.
1862
1877
  */
1863
- static async discover(baseUrl) {
1878
+ static async discover(baseUrl, headers) {
1864
1879
  try {
1865
- const response = await fetch(`${baseUrl}${VERSIONS_ENDPOINT}`);
1880
+ const resolved = resolveHeaders(headers);
1881
+ const response = await fetch(`${baseUrl}${VERSIONS_ENDPOINT}`, {
1882
+ headers: Object.keys(resolved).length > 0 ? resolved : void 0
1883
+ });
1866
1884
  if (!response.ok) return null;
1867
1885
  const info = await response.json();
1868
1886
  const version = this.negotiate(info);
@@ -2694,7 +2712,7 @@ var files = (() => {
2694
2712
  };
2695
2713
 
2696
2714
  // src/lib/version.ts
2697
- var LIBRARY_VERSION = "2.0.0-beta.12";
2715
+ var LIBRARY_VERSION = "2.0.0-beta.14";
2698
2716
  var API_VERSION2 = 2;
2699
2717
 
2700
2718
  // src/lib/interfaces/i-file-system-service.ts
@@ -2707,6 +2725,7 @@ var files = (() => {
2707
2725
  var CWD_KEY = "cwd";
2708
2726
  var HOME_KEY = "home";
2709
2727
  var DEFAULT_HOME = "/";
2728
+ var ANONYMOUS_OWNERSHIP = { uid: "nobody", gid: "nogroup" };
2710
2729
  function createSeedFileSystem() {
2711
2730
  const now = Date.now();
2712
2731
  return {
@@ -2754,6 +2773,88 @@ var files = (() => {
2754
2773
  this.homePath = DEFAULT_HOME;
2755
2774
  this.currentUid = null;
2756
2775
  this.currentGroups = [];
2776
+ this.systemDepth = 0;
2777
+ }
2778
+ // --- Access control ---
2779
+ setAccessPolicy(policy) {
2780
+ this.accessPolicy = policy;
2781
+ }
2782
+ runAsSystem(fn) {
2783
+ this.systemDepth++;
2784
+ try {
2785
+ return fn();
2786
+ } finally {
2787
+ this.systemDepth--;
2788
+ }
2789
+ }
2790
+ reassignOwner(fromUid, toUid) {
2791
+ const from = fromUid.toLowerCase();
2792
+ if (!from || !toUid) return 0;
2793
+ let changed = 0;
2794
+ const visit = (node) => {
2795
+ if (node.ownership && node.ownership.uid.toLowerCase() === from) {
2796
+ node.ownership = { ...node.ownership, uid: toUid };
2797
+ changed++;
2798
+ }
2799
+ node.children?.forEach(visit);
2800
+ };
2801
+ visit(this.root);
2802
+ return changed;
2803
+ }
2804
+ canTraverse(path) {
2805
+ try {
2806
+ this.assertTraverse(this.resolvePath(path), "stat", path);
2807
+ return true;
2808
+ } catch {
2809
+ return false;
2810
+ }
2811
+ }
2812
+ get enforcing() {
2813
+ return !!this.accessPolicy && this.systemDepth === 0;
2814
+ }
2815
+ deny(op, path, reason = "Permission denied") {
2816
+ throw new CliAccessDeniedError(`${op}: ${path}: ${reason}`);
2817
+ }
2818
+ /** `x` on every existing directory on the way to `resolved` (excluding the target). */
2819
+ assertTraverse(resolved, op, display) {
2820
+ if (!this.enforcing) return;
2821
+ const parts = resolved.split("/").filter(Boolean);
2822
+ let current = this.root;
2823
+ for (let i = 0; i < parts.length; i++) {
2824
+ if (!current || current.type !== "directory") return;
2825
+ if (!this.accessPolicy.canAccess(current, "execute")) this.deny(op, display);
2826
+ current = current.children?.find((c) => c.name === parts[i]);
2827
+ }
2828
+ }
2829
+ assertAccess(node, action, op, display) {
2830
+ if (this.enforcing && !this.accessPolicy.canAccess(node, action)) this.deny(op, display);
2831
+ }
2832
+ /** Recursive delete: every directory inside must allow removing its entries (`w` + `x`, readable). */
2833
+ assertRemovableTree(dir, dirPath, display) {
2834
+ if (!this.enforcing) return;
2835
+ this.assertAccess(dir, "read", "rm", display);
2836
+ this.assertAccess(dir, "execute", "rm", display);
2837
+ if ((dir.children?.length ?? 0) > 0) this.assertAccess(dir, "write", "rm", display);
2838
+ for (const child of dir.children ?? []) {
2839
+ if (child.type === "directory") this.assertRemovableTree(child, `${dirPath}/${child.name}`, display);
2840
+ }
2841
+ }
2842
+ /** Copying reads everything it copies: `r` on every file, `r` + `x` on every directory. */
2843
+ assertReadableTree(node, display) {
2844
+ if (!this.enforcing) return;
2845
+ this.assertAccess(node, "read", "cp", display);
2846
+ if (node.type !== "directory") return;
2847
+ this.assertAccess(node, "execute", "cp", display);
2848
+ for (const child of node.children ?? []) {
2849
+ this.assertReadableTree(child, `${display.replace(/\/+$/, "")}/${child.name}`);
2850
+ }
2851
+ }
2852
+ /** Creating/removing entries needs `w` and `x` on the containing directory. */
2853
+ assertModifyDir(dir, dirPath, op, display) {
2854
+ if (!this.enforcing) return;
2855
+ this.assertTraverse(dirPath, op, display);
2856
+ this.assertAccess(dir, "execute", op, display);
2857
+ this.assertAccess(dir, "write", op, display);
2757
2858
  }
2758
2859
  // --- User context ---
2759
2860
  setCurrentUser(uid, groups) {
@@ -2761,7 +2862,9 @@ var files = (() => {
2761
2862
  this.currentGroups = groups;
2762
2863
  }
2763
2864
  getDefaultOwnership() {
2764
- if (!this.currentUid) return void 0;
2865
+ if (!this.currentUid) {
2866
+ return this.accessPolicy ? { ...ANONYMOUS_OWNERSHIP } : void 0;
2867
+ }
2765
2868
  return {
2766
2869
  uid: this.currentUid,
2767
2870
  gid: this.currentGroups[0] || "users"
@@ -2780,6 +2883,8 @@ var files = (() => {
2780
2883
  if (node.type !== "directory") {
2781
2884
  throw new Error(`cd: ${path}: Not a directory`);
2782
2885
  }
2886
+ this.assertTraverse(resolved, "cd", path);
2887
+ this.assertAccess(node, "execute", "cd", path);
2783
2888
  this.cwd = resolved;
2784
2889
  }
2785
2890
  getHomePath() {
@@ -2836,6 +2941,8 @@ var files = (() => {
2836
2941
  if (node.type !== "directory") {
2837
2942
  throw new Error(`ls: ${path}: Not a directory`);
2838
2943
  }
2944
+ this.assertTraverse(this.resolvePath(path), "ls", path);
2945
+ this.assertAccess(node, "read", "ls", path);
2839
2946
  return node.children || [];
2840
2947
  }
2841
2948
  readFile(path) {
@@ -2846,6 +2953,8 @@ var files = (() => {
2846
2953
  if (node.type === "directory") {
2847
2954
  throw new Error(`cat: ${path}: Is a directory`);
2848
2955
  }
2956
+ this.assertTraverse(this.resolvePath(path), "cat", path);
2957
+ this.assertAccess(node, "read", "cat", path);
2849
2958
  return node.content ?? "";
2850
2959
  }
2851
2960
  exists(path) {
@@ -2870,6 +2979,10 @@ var files = (() => {
2870
2979
  }
2871
2980
  let child = current.children.find((c) => c.name === part);
2872
2981
  if (!child) {
2982
+ if (this.enforcing) {
2983
+ this.assertAccess(current, "execute", "mkdir", path);
2984
+ this.assertAccess(current, "write", "mkdir", path);
2985
+ }
2873
2986
  const now = Date.now();
2874
2987
  child = {
2875
2988
  name: part,
@@ -2885,6 +2998,8 @@ var files = (() => {
2885
2998
  current.modifiedAt = now;
2886
2999
  } else if (child.type !== "directory") {
2887
3000
  throw new Error(`mkdir: ${part}: Not a directory`);
3001
+ } else {
3002
+ this.assertAccess(child, "execute", "mkdir", path);
2888
3003
  }
2889
3004
  current = child;
2890
3005
  }
@@ -2903,6 +3018,7 @@ var files = (() => {
2903
3018
  if (parent.children?.find((c) => c.name === dirName)) {
2904
3019
  throw new Error(`mkdir: ${path}: File exists`);
2905
3020
  }
3021
+ this.assertModifyDir(parent, parentPath, "mkdir", path);
2906
3022
  const now = Date.now();
2907
3023
  if (!parent.children) {
2908
3024
  parent.children = [];
@@ -2937,6 +3053,12 @@ var files = (() => {
2937
3053
  }
2938
3054
  const existing = parent.children?.find((c) => c.name === fileName);
2939
3055
  const now = Date.now();
3056
+ if (existing) {
3057
+ this.assertTraverse(resolved, "touch", path);
3058
+ this.assertAccess(existing, "write", "touch", path);
3059
+ } else {
3060
+ this.assertModifyDir(parent, parentPath, "touch", path);
3061
+ }
2940
3062
  if (existing) {
2941
3063
  existing.modifiedAt = now;
2942
3064
  } else {
@@ -2963,6 +3085,8 @@ var files = (() => {
2963
3085
  if (node.type === "directory") {
2964
3086
  throw new Error(`write: ${path}: Is a directory`);
2965
3087
  }
3088
+ this.assertTraverse(resolved, "write", path);
3089
+ this.assertAccess(node, "write", "write", path);
2966
3090
  const now = Date.now();
2967
3091
  node.content = append ? (node.content ?? "") + content : content;
2968
3092
  node.size = new Blob([node.content]).size;
@@ -2991,6 +3115,8 @@ var files = (() => {
2991
3115
  if (target.type === "directory" && !recursive) {
2992
3116
  throw new Error(`rm: ${path}: Is a directory`);
2993
3117
  }
3118
+ this.assertModifyDir(parent, parentPath, "rm", path);
3119
+ if (target.type === "directory") this.assertRemovableTree(target, resolved, path);
2994
3120
  parent.children.splice(index, 1);
2995
3121
  parent.modifiedAt = Date.now();
2996
3122
  }
@@ -3005,10 +3131,13 @@ var files = (() => {
3005
3131
  `cp: -r not specified; omitting directory '${src}'`
3006
3132
  );
3007
3133
  }
3134
+ this.assertTraverse(srcResolved, "cp", src);
3135
+ this.assertReadableTree(srcNode, src);
3008
3136
  const destResolved = this.resolvePath(dest);
3009
3137
  const destNode = this.getNode(destResolved);
3010
3138
  if (destNode && destNode.type === "directory") {
3011
- const clone = this.cloneNode(srcNode);
3139
+ this.assertModifyDir(destNode, destResolved, "cp", dest);
3140
+ const clone = this.ownedByCurrentUser(this.cloneNode(srcNode));
3012
3141
  if (!destNode.children) {
3013
3142
  destNode.children = [];
3014
3143
  }
@@ -3028,7 +3157,8 @@ var files = (() => {
3028
3157
  if (!parent || parent.type !== "directory") {
3029
3158
  throw new Error(`cp: ${parentPath}: No such file or directory`);
3030
3159
  }
3031
- const clone = this.cloneNode(srcNode);
3160
+ this.assertModifyDir(parent, parentPath, "cp", dest);
3161
+ const clone = this.ownedByCurrentUser(this.cloneNode(srcNode));
3032
3162
  clone.name = newName;
3033
3163
  if (!parent.children) {
3034
3164
  parent.children = [];
@@ -3060,10 +3190,12 @@ var files = (() => {
3060
3190
  if (!srcParent || !srcParent.children) {
3061
3191
  throw new Error(`mv: ${src}: No such file or directory`);
3062
3192
  }
3193
+ this.assertModifyDir(srcParent, srcParentPath, "mv", src);
3063
3194
  const srcIndex = srcParent.children.findIndex(
3064
3195
  (c) => c.name === srcNode.name
3065
3196
  );
3066
3197
  if (destNode && destNode.type === "directory") {
3198
+ this.assertModifyDir(destNode, destResolved, "mv", dest);
3067
3199
  if (!destNode.children) {
3068
3200
  destNode.children = [];
3069
3201
  }
@@ -3086,6 +3218,7 @@ var files = (() => {
3086
3218
  `mv: ${destParentPath}: No such file or directory`
3087
3219
  );
3088
3220
  }
3221
+ this.assertModifyDir(destParent, destParentPath, "mv", dest);
3089
3222
  srcParent.children.splice(srcIndex, 1);
3090
3223
  srcNode.name = newName;
3091
3224
  if (!destParent.children) {
@@ -3109,6 +3242,9 @@ var files = (() => {
3109
3242
  if (!node) {
3110
3243
  throw new Error(`chmod: ${path}: No such file or directory`);
3111
3244
  }
3245
+ if (this.enforcing && !this.accessPolicy.canChangeOwnership(node)) {
3246
+ this.deny("chmod", path, "Operation not permitted");
3247
+ }
3112
3248
  node.permissions = permissions;
3113
3249
  }
3114
3250
  chown(path, ownership) {
@@ -3117,6 +3253,9 @@ var files = (() => {
3117
3253
  if (!node) {
3118
3254
  throw new Error(`chown: ${path}: No such file or directory`);
3119
3255
  }
3256
+ if (this.enforcing && !this.accessPolicy.canChangeOwnership(node, ownership)) {
3257
+ this.deny("chown", path, "Operation not permitted");
3258
+ }
3120
3259
  node.ownership = ownership;
3121
3260
  }
3122
3261
  // --- Persistence ---
@@ -3158,6 +3297,18 @@ var files = (() => {
3158
3297
  }
3159
3298
  }
3160
3299
  // --- Private helpers ---
3300
+ /** A copy belongs to whoever made it (like `cp` without `-p`) */
3301
+ ownedByCurrentUser(node) {
3302
+ const owner = this.getDefaultOwnership();
3303
+ if (owner) {
3304
+ const apply = (n) => {
3305
+ n.ownership = { ...owner };
3306
+ n.children?.forEach(apply);
3307
+ };
3308
+ apply(node);
3309
+ }
3310
+ return node;
3311
+ }
3161
3312
  cloneNode(node) {
3162
3313
  const now = Date.now();
3163
3314
  const clone = {
@@ -3309,7 +3460,7 @@ var files = (() => {
3309
3460
  ];
3310
3461
  }
3311
3462
  async processCommand(command, context) {
3312
- const fs = context.services.get(
3463
+ const fs = context.services.getRequired(
3313
3464
  IFileSystemService_TOKEN
3314
3465
  );
3315
3466
  const targetPath = command.value || fs.getCurrentDirectory();
@@ -3382,7 +3533,7 @@ var files = (() => {
3382
3533
  this.metadata = { icon: "\u{1F4C1}", module: "file management" };
3383
3534
  }
3384
3535
  async processCommand(command, context) {
3385
- const fs = context.services.get(
3536
+ const fs = context.services.getRequired(
3386
3537
  IFileSystemService_TOKEN
3387
3538
  );
3388
3539
  const target = command.value || "~";
@@ -3405,7 +3556,7 @@ var files = (() => {
3405
3556
  this.metadata = { icon: "\u{1F4C2}", module: "file management" };
3406
3557
  }
3407
3558
  async processCommand(command, context) {
3408
- const fs = context.services.get(
3559
+ const fs = context.services.getRequired(
3409
3560
  IFileSystemService_TOKEN
3410
3561
  );
3411
3562
  context.writer.writeln(fs.getCurrentDirectory());
@@ -3433,7 +3584,7 @@ var files = (() => {
3433
3584
  ];
3434
3585
  }
3435
3586
  async processCommand(command, context) {
3436
- const fs = context.services.get(
3587
+ const fs = context.services.getRequired(
3437
3588
  IFileSystemService_TOKEN
3438
3589
  );
3439
3590
  const path = command.value;
@@ -3463,7 +3614,7 @@ var files = (() => {
3463
3614
  this.metadata = { icon: "\u{1F5D1}", module: "file management" };
3464
3615
  }
3465
3616
  async processCommand(command, context) {
3466
- const fs = context.services.get(
3617
+ const fs = context.services.getRequired(
3467
3618
  IFileSystemService_TOKEN
3468
3619
  );
3469
3620
  const path = command.value;
@@ -3509,7 +3660,7 @@ var files = (() => {
3509
3660
  this.metadata = { icon: "\u{1F4C4}", module: "file management" };
3510
3661
  }
3511
3662
  async processCommand(command, context) {
3512
- const fs = context.services.get(
3663
+ const fs = context.services.getRequired(
3513
3664
  IFileSystemService_TOKEN
3514
3665
  );
3515
3666
  const path = command.value;
@@ -3538,7 +3689,7 @@ var files = (() => {
3538
3689
  this.metadata = { icon: "\u{1F4D6}", module: "file management" };
3539
3690
  }
3540
3691
  async processCommand(command, context) {
3541
- const fs = context.services.get(
3692
+ const fs = context.services.getRequired(
3542
3693
  IFileSystemService_TOKEN
3543
3694
  );
3544
3695
  const path = command.value;
@@ -3579,7 +3730,7 @@ var files = (() => {
3579
3730
  }
3580
3731
  return;
3581
3732
  }
3582
- const fs = context.services.get(
3733
+ const fs = context.services.getRequired(
3583
3734
  IFileSystemService_TOKEN
3584
3735
  );
3585
3736
  let text;
@@ -3653,7 +3804,7 @@ var files = (() => {
3653
3804
  ];
3654
3805
  }
3655
3806
  async processCommand(command, context) {
3656
- const fs = context.services.get(
3807
+ const fs = context.services.getRequired(
3657
3808
  IFileSystemService_TOKEN
3658
3809
  );
3659
3810
  const path = command.value;
@@ -3704,7 +3855,7 @@ var files = (() => {
3704
3855
  ];
3705
3856
  }
3706
3857
  async processCommand(command, context) {
3707
- const fs = context.services.get(
3858
+ const fs = context.services.getRequired(
3708
3859
  IFileSystemService_TOKEN
3709
3860
  );
3710
3861
  const recursive = command.args["recursive"] || command.args["r"] || command.args["R"];
@@ -3742,7 +3893,7 @@ var files = (() => {
3742
3893
  this.metadata = { icon: "\u{1F4E6}", module: "file management" };
3743
3894
  }
3744
3895
  async processCommand(command, context) {
3745
- const fs = context.services.get(
3896
+ const fs = context.services.getRequired(
3746
3897
  IFileSystemService_TOKEN
3747
3898
  );
3748
3899
  const parts = this.parseArgs(command);
@@ -3766,6 +3917,16 @@ var files = (() => {
3766
3917
  }
3767
3918
  };
3768
3919
 
3920
+ // src/lib/utils/readable-children.ts
3921
+ function readableChildren(fs, path) {
3922
+ try {
3923
+ return fs.listDirectory(path);
3924
+ } catch (e) {
3925
+ if (isCliAccessDeniedError(e)) return null;
3926
+ throw e;
3927
+ }
3928
+ }
3929
+
3769
3930
  // src/lib/processors/cli-tree-command-processor.ts
3770
3931
  var CliTreeCommandProcessor = class {
3771
3932
  constructor() {
@@ -3786,7 +3947,7 @@ var files = (() => {
3786
3947
  ];
3787
3948
  }
3788
3949
  async processCommand(command, context) {
3789
- const fs = context.services.get(
3950
+ const fs = context.services.getRequired(
3790
3951
  IFileSystemService_TOKEN
3791
3952
  );
3792
3953
  const targetPath = command.value || fs.getCurrentDirectory();
@@ -3813,7 +3974,8 @@ var files = (() => {
3813
3974
  )
3814
3975
  );
3815
3976
  const counts = { dirs: 0, files: 0 };
3816
- this.printTree(node, "", true, 0, maxDepth, context, counts);
3977
+ this.fs = fs;
3978
+ this.printTree(node, "", true, 0, maxDepth, context, counts, resolvedPath);
3817
3979
  context.writer.writeln();
3818
3980
  context.writer.writeln(
3819
3981
  `${counts.dirs} directories, ${counts.files} files`
@@ -3822,11 +3984,15 @@ var files = (() => {
3822
3984
  context.writer.writeError(e.message);
3823
3985
  }
3824
3986
  }
3825
- printTree(node, prefix, isRoot, depth, maxDepth, context, counts) {
3826
- if (!node.children || depth >= maxDepth) {
3987
+ printTree(node, prefix, isRoot, depth, maxDepth, context, counts, path = "/") {
3988
+ if (depth >= maxDepth) {
3989
+ return;
3990
+ }
3991
+ const visible = this.fs ? readableChildren(this.fs, path) : node.children;
3992
+ if (!visible) {
3827
3993
  return;
3828
3994
  }
3829
- const children = [...node.children].sort((a, b) => {
3995
+ const children = [...visible].sort((a, b) => {
3830
3996
  if (a.type !== b.type) {
3831
3997
  return a.type === "directory" ? -1 : 1;
3832
3998
  }
@@ -3851,7 +4017,8 @@ var files = (() => {
3851
4017
  depth + 1,
3852
4018
  maxDepth,
3853
4019
  context,
3854
- counts
4020
+ counts,
4021
+ path === "/" ? `/${child.name}` : `${path}/${child.name}`
3855
4022
  );
3856
4023
  } else {
3857
4024
  counts.files++;
@@ -3881,7 +4048,7 @@ var files = (() => {
3881
4048
  ];
3882
4049
  }
3883
4050
  async processCommand(command, context) {
3884
- const fs = context.services.get(
4051
+ const fs = context.services.getRequired(
3885
4052
  IFileSystemService_TOKEN
3886
4053
  );
3887
4054
  const count = parseInt(
@@ -3948,7 +4115,7 @@ var files = (() => {
3948
4115
  ];
3949
4116
  }
3950
4117
  async processCommand(command, context) {
3951
- const fs = context.services.get(
4118
+ const fs = context.services.getRequired(
3952
4119
  IFileSystemService_TOKEN
3953
4120
  );
3954
4121
  const count = parseInt(
@@ -4029,7 +4196,7 @@ var files = (() => {
4029
4196
  ];
4030
4197
  }
4031
4198
  async processCommand(command, context) {
4032
- const fs = context.services.get(
4199
+ const fs = context.services.getRequired(
4033
4200
  IFileSystemService_TOKEN
4034
4201
  );
4035
4202
  const showLines = command.args["lines"] || command.args["l"] || false;
@@ -4125,7 +4292,7 @@ var files = (() => {
4125
4292
  ];
4126
4293
  }
4127
4294
  async processCommand(command, context) {
4128
- const fs = context.services.get(
4295
+ const fs = context.services.getRequired(
4129
4296
  IFileSystemService_TOKEN
4130
4297
  );
4131
4298
  const searchPath = this.parseSearchPath(command) || fs.getCurrentDirectory();
@@ -4149,6 +4316,7 @@ var files = (() => {
4149
4316
  const resolvedBase = fs.resolvePath(searchPath);
4150
4317
  const nameRegex = namePattern ? this.globToRegex(namePattern) : null;
4151
4318
  const results = [];
4319
+ this.fs = fs;
4152
4320
  this.walk(
4153
4321
  node,
4154
4322
  resolvedBase,
@@ -4176,8 +4344,9 @@ var files = (() => {
4176
4344
  return new RegExp(`^${regexStr}$`, "i");
4177
4345
  }
4178
4346
  walk(node, currentPath, depth, maxDepth, nameRegex, typeFilter, results) {
4179
- if (!node.children) return;
4180
- for (const child of node.children) {
4347
+ const children = this.fs ? readableChildren(this.fs, currentPath) : node.children;
4348
+ if (!children) return;
4349
+ for (const child of children) {
4181
4350
  const childPath = currentPath === "/" ? `/${child.name}` : `${currentPath}/${child.name}`;
4182
4351
  let matches = true;
4183
4352
  if (nameRegex && !nameRegex.test(child.name)) {
@@ -4262,7 +4431,7 @@ var files = (() => {
4262
4431
  ];
4263
4432
  }
4264
4433
  async processCommand(command, context) {
4265
- const fs = context.services.get(
4434
+ const fs = context.services.getRequired(
4266
4435
  IFileSystemService_TOKEN
4267
4436
  );
4268
4437
  const ignoreCase = command.args["ignore-case"] || command.args["i"] || false;
@@ -4410,8 +4579,9 @@ var files = (() => {
4410
4579
  };
4411
4580
  }
4412
4581
  collectFiles(fs, basePath, node, result) {
4413
- if (!node.children) return;
4414
- for (const child of node.children) {
4582
+ const children = readableChildren(fs, basePath);
4583
+ if (!children) return;
4584
+ for (const child of children) {
4415
4585
  const childPath = basePath === "/" ? `/${child.name}` : `${basePath}/${child.name}`;
4416
4586
  if (child.type === "file") {
4417
4587
  result.push(childPath);
@@ -4443,7 +4613,7 @@ var files = (() => {
4443
4613
  ];
4444
4614
  }
4445
4615
  async processCommand(command, context) {
4446
- const fs = context.services.get(
4616
+ const fs = context.services.getRequired(
4447
4617
  IFileSystemService_TOKEN
4448
4618
  );
4449
4619
  let filePath = (command.value || "").trim();
@@ -4571,7 +4741,6 @@ var files = (() => {
4571
4741
  }
4572
4742
 
4573
4743
  // src/cli-entrypoint.ts
4574
- var fsService = new IndexedDbFileSystemService();
4575
4744
  var module = {
4576
4745
  apiVersion: API_VERSION2,
4577
4746
  name: "@qodalis/cli-files",
@@ -4598,16 +4767,17 @@ var files = (() => {
4598
4767
  services: [
4599
4768
  {
4600
4769
  provide: IFileSystemService_TOKEN,
4601
- useValue: fsService
4770
+ useClass: IndexedDbFileSystemService
4602
4771
  },
4603
4772
  {
4604
4773
  provide: ICliCompletionProvider_TOKEN,
4605
- useValue: new FilePathCompletionProvider(fsService),
4774
+ useClass: FilePathCompletionProvider,
4775
+ deps: [IFileSystemService_TOKEN],
4606
4776
  multi: true
4607
4777
  }
4608
4778
  ],
4609
4779
  async onInit(context) {
4610
- const fs = context.services.get(
4780
+ const fs = context.services.getRequired(
4611
4781
  IFileSystemService_TOKEN
4612
4782
  );
4613
4783
  await fs.initialize();