From 917c55b9f1180594911a11ab1bd07ac1853511da Mon Sep 17 00:00:00 2001
From: Maxime Dufour <maxime.dufour@outscale.com>
Date: Thu, 26 Oct 2023 12:52:48 +0000
Subject: [PATCH] First draft of support osc-cost

Signed-off-by: Maxime Dufour <maxime.dufour@outscale.com>
---
 package-lock.json                    | 263 ++++++++++++++++++----
 package.json                         |  16 +-
 src/components/osc_cost.ts           | 313 +++++++++++++++++++++++++++
 src/components/shell.ts              | 131 +++++++++++
 src/configuration/utils.ts           |   1 +
 src/explorer.ts                      |  24 +-
 src/flat/folders/node.folder.ts      |   3 +
 src/flat/node.profile.ts             |   5 +-
 src/flat/node.ts                     |   2 +
 src/flat/resources/node.resources.ts |   3 +
 10 files changed, 713 insertions(+), 48 deletions(-)
 create mode 100644 src/components/osc_cost.ts
 create mode 100644 src/components/shell.ts

diff --git a/package-lock.json b/package-lock.json
index b98674a..9c20c27 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,6 +13,7 @@
         "cross-fetch": "^3.1.5",
         "outscale-api": "^0.11.0",
         "rxjs": "^7.5.7",
+        "shelljs": "^0.8.5",
         "true-myth": "^6.2.0"
       },
       "devDependencies": {
@@ -20,6 +21,7 @@
         "@types/glob": "^7.2.0",
         "@types/mocha": "^9.1.1",
         "@types/node": "14.x",
+        "@types/shelljs": "^0.8.11",
         "@types/sinon": "^10.0.13",
         "@types/vscode": "^1.73.0",
         "@typescript-eslint/eslint-plugin": "^5.21.0",
@@ -303,6 +305,16 @@
         "@types/ws": "*"
       }
     },
+    "node_modules/@types/shelljs": {
+      "version": "0.8.15",
+      "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.15.tgz",
+      "integrity": "sha512-vzmnCHl6hViPu9GNLQJ+DZFd6BQI2DBTUeOvYHqkWQLMfKAAQYMb/xAmZkTogZI/vqXHCWkqDRymDI5p0QTi5Q==",
+      "dev": true,
+      "dependencies": {
+        "@types/glob": "~7.2.0",
+        "@types/node": "*"
+      }
+    },
     "node_modules/@types/sinon": {
       "version": "10.0.13",
       "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.13.tgz",
@@ -901,8 +913,7 @@
     "node_modules/balanced-match": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
-      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
-      "dev": true
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
     },
     "node_modules/base64-js": {
       "version": "1.5.1",
@@ -993,7 +1004,6 @@
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
       "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-      "dev": true,
       "dependencies": {
         "balanced-match": "^1.0.0",
         "concat-map": "0.0.1"
@@ -1394,8 +1404,7 @@
     "node_modules/concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
-      "dev": true
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
     },
     "node_modules/core-util-is": {
       "version": "1.0.3",
@@ -2276,8 +2285,7 @@
     "node_modules/fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
-      "dev": true
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
     },
     "node_modules/fstream": {
       "version": "1.0.12",
@@ -2327,10 +2335,12 @@
       }
     },
     "node_modules/function-bind": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
-      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
-      "dev": true
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
     },
     "node_modules/functional-red-black-tree": {
       "version": "1.0.1",
@@ -2566,6 +2576,17 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/hasown": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
+      "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
+      "dependencies": {
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
     "node_modules/he": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
@@ -2725,7 +2746,6 @@
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
       "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
-      "dev": true,
       "dependencies": {
         "once": "^1.3.0",
         "wrappy": "1"
@@ -2734,8 +2754,7 @@
     "node_modules/inherits": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-      "dev": true
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
     },
     "node_modules/ini": {
       "version": "1.3.8",
@@ -2743,6 +2762,14 @@
       "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
       "dev": true
     },
+    "node_modules/interpret": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
+      "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
     "node_modules/is-binary-path": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -2767,6 +2794,17 @@
         "is-ci": "bin.js"
       }
     },
+    "node_modules/is-core-module": {
+      "version": "2.13.1",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
+      "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
+      "dependencies": {
+        "hasown": "^2.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/is-docker": {
       "version": "2.2.1",
       "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
@@ -3191,7 +3229,6 @@
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
       "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
-      "dev": true,
       "dependencies": {
         "brace-expansion": "^1.1.7"
       },
@@ -3529,7 +3566,6 @@
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
       "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
-      "dev": true,
       "dependencies": {
         "wrappy": "1"
       }
@@ -3702,7 +3738,6 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
       "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
-      "dev": true,
       "engines": {
         "node": ">=0.10.0"
       }
@@ -3716,6 +3751,11 @@
         "node": ">=8"
       }
     },
+    "node_modules/path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
+    },
     "node_modules/path-to-regexp": {
       "version": "1.8.0",
       "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
@@ -4014,6 +4054,17 @@
         "node": ">=8.10.0"
       }
     },
+    "node_modules/rechoir": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+      "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==",
+      "dependencies": {
+        "resolve": "^1.1.6"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
     "node_modules/regexpp": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
@@ -4035,6 +4086,22 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/resolve": {
+      "version": "1.22.8",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+      "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
+      "dependencies": {
+        "is-core-module": "^2.13.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/resolve-alpn": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
@@ -4250,6 +4317,41 @@
         "node": ">=8"
       }
     },
+    "node_modules/shelljs": {
+      "version": "0.8.5",
+      "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz",
+      "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==",
+      "dependencies": {
+        "glob": "^7.0.0",
+        "interpret": "^1.0.0",
+        "rechoir": "^0.6.2"
+      },
+      "bin": {
+        "shjs": "bin/shjs"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/shelljs/node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
     "node_modules/side-channel": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
@@ -4422,6 +4524,17 @@
         "node": ">=8"
       }
     },
+    "node_modules/supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/tar-fs": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
@@ -5059,8 +5172,7 @@
     "node_modules/wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
-      "dev": true
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
     },
     "node_modules/ws": {
       "version": "8.12.0",
@@ -5422,6 +5534,16 @@
         "@types/ws": "*"
       }
     },
+    "@types/shelljs": {
+      "version": "0.8.15",
+      "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.15.tgz",
+      "integrity": "sha512-vzmnCHl6hViPu9GNLQJ+DZFd6BQI2DBTUeOvYHqkWQLMfKAAQYMb/xAmZkTogZI/vqXHCWkqDRymDI5p0QTi5Q==",
+      "dev": true,
+      "requires": {
+        "@types/glob": "~7.2.0",
+        "@types/node": "*"
+      }
+    },
     "@types/sinon": {
       "version": "10.0.13",
       "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.13.tgz",
@@ -5838,8 +5960,7 @@
     "balanced-match": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
-      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
-      "dev": true
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
     },
     "base64-js": {
       "version": "1.5.1",
@@ -5909,7 +6030,6 @@
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
       "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-      "dev": true,
       "requires": {
         "balanced-match": "^1.0.0",
         "concat-map": "0.0.1"
@@ -6217,8 +6337,7 @@
     "concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
-      "dev": true
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
     },
     "core-util-is": {
       "version": "1.0.3",
@@ -6880,8 +6999,7 @@
     "fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
-      "dev": true
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
     },
     "fstream": {
       "version": "1.0.12",
@@ -6921,10 +7039,9 @@
       }
     },
     "function-bind": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
-      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
-      "dev": true
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
     },
     "functional-red-black-tree": {
       "version": "1.0.1",
@@ -7099,6 +7216,14 @@
       "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
       "dev": true
     },
+    "hasown": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
+      "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
+      "requires": {
+        "function-bind": "^1.1.2"
+      }
+    },
     "he": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
@@ -7207,7 +7332,6 @@
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
       "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
-      "dev": true,
       "requires": {
         "once": "^1.3.0",
         "wrappy": "1"
@@ -7216,8 +7340,7 @@
     "inherits": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-      "dev": true
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
     },
     "ini": {
       "version": "1.3.8",
@@ -7225,6 +7348,11 @@
       "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
       "dev": true
     },
+    "interpret": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
+      "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA=="
+    },
     "is-binary-path": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -7243,6 +7371,14 @@
         "ci-info": "^2.0.0"
       }
     },
+    "is-core-module": {
+      "version": "2.13.1",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
+      "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
+      "requires": {
+        "hasown": "^2.0.0"
+      }
+    },
     "is-docker": {
       "version": "2.2.1",
       "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
@@ -7570,7 +7706,6 @@
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
       "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
-      "dev": true,
       "requires": {
         "brace-expansion": "^1.1.7"
       }
@@ -7829,7 +7964,6 @@
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
       "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
-      "dev": true,
       "requires": {
         "wrappy": "1"
       }
@@ -7961,8 +8095,7 @@
     "path-is-absolute": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
-      "dev": true
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="
     },
     "path-key": {
       "version": "3.1.1",
@@ -7970,6 +8103,11 @@
       "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
       "dev": true
     },
+    "path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
+    },
     "path-to-regexp": {
       "version": "1.8.0",
       "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
@@ -8202,6 +8340,14 @@
         "picomatch": "^2.2.1"
       }
     },
+    "rechoir": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+      "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==",
+      "requires": {
+        "resolve": "^1.1.6"
+      }
+    },
     "regexpp": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
@@ -8214,6 +8360,16 @@
       "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
       "dev": true
     },
+    "resolve": {
+      "version": "1.22.8",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+      "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
+      "requires": {
+        "is-core-module": "^2.13.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      }
+    },
     "resolve-alpn": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
@@ -8363,6 +8519,31 @@
       "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
       "dev": true
     },
+    "shelljs": {
+      "version": "0.8.5",
+      "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz",
+      "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==",
+      "requires": {
+        "glob": "^7.0.0",
+        "interpret": "^1.0.0",
+        "rechoir": "^0.6.2"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.2.3",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+          "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.1.1",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        }
+      }
+    },
     "side-channel": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
@@ -8481,6 +8662,11 @@
         "has-flag": "^4.0.0"
       }
     },
+    "supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
+    },
     "tar-fs": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
@@ -9003,8 +9189,7 @@
     "wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
-      "dev": true
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
     },
     "ws": {
       "version": "8.12.0",
diff --git a/package.json b/package.json
index 60e4ef4..5c9dccb 100644
--- a/package.json
+++ b/package.json
@@ -63,6 +63,16 @@
           "type": "object",
           "default": {},
           "description": "%osc-viewer.filters%"
+        },
+        "osc-viewer.costEstimation.enabled": {
+          "type": "boolean",
+          "default": false,
+          "description": "%osc-viewer.costEstimation.enabled%"
+        },
+        "osc-viewer.costEstimation.oscCostPath": {
+          "type": "string",
+          "default": "",
+          "description": "%osc-viewer.costEstimation.oscCostPath%"
         }
       }
     },
@@ -358,8 +368,8 @@
   },
   "scripts": {
     "vscode:prepublish": "npm run ${MOCK}esbuild-base -- --minify",
-    "esbuild-base": "esbuild ./src/extension.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node",
-    "mock-esbuild-base": "esbuild ./src/mockExtension.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node",
+    "esbuild-base": "esbuild ./src/extension.ts --bundle --outfile=out/main.js --external:vscode --external:shelljs --format=cjs --platform=node",
+    "mock-esbuild-base": "esbuild ./src/mockExtension.ts --bundle --outfile=out/main.js --external:vscode --external:shelljs --format=cjs --platform=node",
     "esbuild": "npm run esbuild-base -- --sourcemap",
     "esbuild-watch": "npm run esbuild-base -- --sourcemap --watch",
     "docker-build-ui-test": "docker build -f src/ui-test/Dockerfile  -t vscode-osc-viewer-test:latest .",
@@ -379,6 +389,7 @@
     "@types/glob": "^7.2.0",
     "@types/mocha": "^9.1.1",
     "@types/node": "14.x",
+    "@types/shelljs": "^0.8.11",
     "@types/sinon": "^10.0.13",
     "@types/vscode": "^1.73.0",
     "@typescript-eslint/eslint-plugin": "^5.21.0",
@@ -405,6 +416,7 @@
     "cross-fetch": "^3.1.5",
     "outscale-api": "^0.11.0",
     "rxjs": "^7.5.7",
+    "shelljs": "^0.8.5",
     "true-myth": "^6.2.0"
   }
 }
\ No newline at end of file
diff --git a/src/components/osc_cost.ts b/src/components/osc_cost.ts
new file mode 100644
index 0000000..9ce4856
--- /dev/null
+++ b/src/components/osc_cost.ts
@@ -0,0 +1,313 @@
+import * as vscode from 'vscode';
+import { getConfigurationParameter, OSC_COST_PARAMETER } from "../configuration/utils";
+import { pathExists } from "../config_file/utils";
+import { ACCESSKEY_FOLDER_NAME } from "../flat/folders/simple/node.folder.accesskey";
+import { APIACCESSRULES_FOLDER_NAME } from "../flat/folders/simple/node.folder.apiaccessrule";
+import { CA_FOLDER_NAME } from "../flat/folders/simple/node.folder.ca";
+import { CLIENTGATEWAYS_FOLDER_NAME } from "../flat/folders/simple/node.folder.clientgateway";
+import { DHCPOPTIONS_FOLDER_NAME } from "../flat/folders/simple/node.folder.dhcpoption";
+import { DIRECTLINKS_FOLDER_NAME } from "../flat/folders/simple/node.folder.directlink";
+import { DIRECTLINKINTERFACES_FOLDER_NAME } from "../flat/folders/simple/node.folder.directlinkinterface";
+import { IMAGES_FOLDER_NAME } from "../flat/folders/simple/node.folder.image";
+import { KEYPAIRS_FOLDER_NAME } from "../flat/folders/simple/node.folder.keypair";
+import { LOADBALANCER_FOLDER_NAME } from "../flat/folders/simple/node.folder.loadbalancer";
+import { NATSERVICES_FOLDER_NAME } from "../flat/folders/simple/node.folder.natservice";
+import { NETACCESSPOINTS_FOLDER_NAME } from "../flat/folders/simple/node.folder.netaccesspoint";
+import { NETPEERINGS_FOLDER_NAME } from "../flat/folders/simple/node.folder.netpeering";
+import { SNAPSHOTS_FOLDER_NAME } from "../flat/folders/simple/node.folder.snapshot";
+import { SUBNETS_FOLDER_NAME } from "../flat/folders/simple/node.folder.subnet";
+import { VPNCONNECTIONS_FOLDER_NAME } from "../flat/folders/simple/node.folder.vpnconnection";
+import { FLEXIBLEGPUS_FOLDER_NAME } from "../flat/folders/specific/node.folder.flexiblegpu";
+import { INTERNETSERVICES_FOLDER_NAME } from "../flat/folders/specific/node.folder.internetservice";
+import { NET_FOLDER_NAME } from "../flat/folders/specific/node.folder.net";
+import { NICS_FOLDER_NAME } from "../flat/folders/specific/node.folder.nic";
+import { PUBLICIP_FOLDER_NAME } from "../flat/folders/specific/node.folder.publicip";
+import { ROUTETABLES_FOLDER_NAME } from "../flat/folders/specific/node.folder.routetable";
+import { SECURITYGROUPS_FOLDER_NAME } from "../flat/folders/specific/node.folder.securitygroup";
+import { VIRTUALGATEWAYS_FOLDER_NAME } from "../flat/folders/specific/node.folder.virtualgateway";
+import { VM_FOLDER_NAME } from "../flat/folders/specific/node.folder.vm";
+import { VOLUME_FOLDER_NAME } from "../flat/folders/specific/node.folder.volume";
+import { Profile, ResourceNodeType } from "../flat/node";
+import { OutputChannel } from "../logs/output_channel";
+import { shell } from "./shell";
+
+export type ResourceCost = number;
+export type ResourcesTypeCost = { globalPrice: number, values: Map<string, ResourceCost> };
+
+const DEFAULT_OPTIONS_OSC_COST = new Map<string, string>([
+    ['v0.1.0', '--format json'],
+    ['v0.2.0', '--format json --skip-resource Oos'],
+  ]);
+
+export class AccountCost {
+    accountCost: number;
+    region: string;
+    resourcesCost: Map<string, ResourcesTypeCost>;
+
+    constructor() {
+        this.resourcesCost = new Map();
+        this.accountCost = 0;
+        this.region = "";
+    }
+
+    getResourceType(resourceType: string): ResourcesTypeCost | undefined {
+        return this.resourcesCost.get(resourceType);
+    }
+
+    setResourceType(resourceType: string, value: ResourcesTypeCost) {
+        this.resourcesCost.set(resourceType, value);
+    }
+
+    getResourceTypeCost(folderName: string): string | undefined {
+        const resourceType = folderNameToOscCostResourceType(folderName);
+        if (typeof resourceType === 'undefined') {
+            return undefined;
+        }
+        const resourceTypeCost = this.getResourceType(resourceType);
+        if (typeof resourceTypeCost === 'undefined') {
+            return undefined;
+        }
+        return formatPrice(resourceTypeCost.globalPrice, getCurrency(this.region));
+    }
+
+    getResourceIdCost(resourceNodeType: ResourceNodeType, resourceId: string): string | undefined {
+        const resourceType = resourceNodeTypeToOscCostResourceType(resourceNodeType);
+        if (typeof resourceType === 'undefined') {
+            return undefined;
+        }
+
+        const resourceTypeCost = this.getResourceType(resourceType);
+        if (typeof resourceTypeCost === 'undefined') {
+            return undefined;
+        }
+
+        const resourceCost = resourceTypeCost.values.get(resourceId);
+        if (typeof resourceCost === 'undefined') {
+            return undefined;
+        }
+
+        return formatPrice(resourceCost, getCurrency(this.region));
+    }
+
+    getAccountCost(): string {
+        return formatPrice(this.accountCost, getCurrency(this.region));
+    }
+
+
+}
+
+function formatPrice(price: number, currency: string): string {
+    return "~" + price.toFixed(2) + currency;
+}
+
+export function getCurrency(region: string): string {
+    switch (region) {
+        case "eu-west-2":
+        case "cloudgouv-eu-west-1":
+            return "€";
+        case "ap-northeast-1":
+            return "¥";
+        case "us-east-2":
+        case "us-west-1":
+            return "$";
+        default:
+            return "€";
+    }
+}
+
+function folderNameToOscCostResourceType(folderName: string): string | undefined {
+    switch (folderName) {
+        case VM_FOLDER_NAME:
+            return "Vm";
+        case VOLUME_FOLDER_NAME:
+            return "Volume";
+        case PUBLICIP_FOLDER_NAME:
+            return "PublicIp";
+        case SNAPSHOTS_FOLDER_NAME:
+            return "Snapshot";
+        case LOADBALANCER_FOLDER_NAME:
+            return "LoadBalancer";
+        case FLEXIBLEGPUS_FOLDER_NAME:
+            return "FlexibleGpu";
+        case VPNCONNECTIONS_FOLDER_NAME:
+            return "FlexibleGpu";
+        case NATSERVICES_FOLDER_NAME:
+            return "NatServices";
+        case ACCESSKEY_FOLDER_NAME:
+        case CLIENTGATEWAYS_FOLDER_NAME:
+        case IMAGES_FOLDER_NAME:
+        case INTERNETSERVICES_FOLDER_NAME:
+        case KEYPAIRS_FOLDER_NAME:
+        case NET_FOLDER_NAME:
+        case NICS_FOLDER_NAME:
+        case ROUTETABLES_FOLDER_NAME:
+        case SECURITYGROUPS_FOLDER_NAME:
+        case SUBNETS_FOLDER_NAME:
+        case VIRTUALGATEWAYS_FOLDER_NAME:
+        case DHCPOPTIONS_FOLDER_NAME:
+        case DIRECTLINKS_FOLDER_NAME:
+        case DIRECTLINKINTERFACES_FOLDER_NAME:
+        case NETPEERINGS_FOLDER_NAME:
+        case APIACCESSRULES_FOLDER_NAME:
+        case NETACCESSPOINTS_FOLDER_NAME:
+        case CA_FOLDER_NAME:
+            return undefined;
+        default:
+            OutputChannel.getInstance().appendLine(`The folder '${folderName}' is not handle for osc-cost conversion. Report it to the developpers`);
+            return undefined;
+    }
+}
+
+function resourceNodeTypeToOscCostResourceType(resourceNodeType: ResourceNodeType): string | undefined {
+    switch (resourceNodeType) {
+        case 'vms':
+            return "Vm";
+        case 'volumes':
+            return "Volume";
+        case 'eips':
+            return "PublicIp";
+        case 'snapshots':
+            return "Snapshot";
+        case 'loadbalancers':
+            return "LoadBalancer";
+        case 'FlexibleGpu':
+            return "FlexibleGpu";
+        case 'VpnConnection':
+            return "FlexibleGpu";
+        case 'NatService':
+            return "NatServices";
+        case 'AccessKey':
+        case 'ClientGateway':
+        case 'omis':
+        case 'InternetService':
+        case 'keypairs':
+        case 'vpc':
+        case 'Nic':
+        case 'routetables':
+        case 'securitygroups':
+        case 'Subnet':
+        case 'VirtualGateway':
+        case 'DhcpOption':
+        case 'DirectLink':
+        case 'DirectLinkInterface':
+        case 'NetPeering':
+        case 'ApiAccessRule':
+        case 'NetAccessPoint':
+        case 'Ca':
+            return undefined;
+        default:
+            OutputChannel.getInstance().appendLine(`The resourceNodeType '${resourceNodeType}' is not handle for osc-cost conversion. Report it to the developpers`);
+            return undefined;
+    }
+}
+
+
+function jsonToAccountCost(oscCostOutput: string): AccountCost | undefined {
+    const accountCost = new AccountCost();
+    for (const jsonString of oscCostOutput.split('\n')) {
+        OutputChannel.getInstance().appendLine(`The jsonString is ${jsonString}`);
+        let json;
+        try {
+            json = JSON.parse(jsonString);
+        } catch {
+            OutputChannel.getInstance().appendLine(`Could not parse the json string ${jsonString}`);
+            return undefined;
+        }
+
+        if (typeof json === "undefined") {
+            OutputChannel.getInstance().appendLine(`Could not parse the json string ${jsonString}`);
+            return undefined;
+        }
+
+        //OutputChannel.getInstance().appendLine(`The json is  ${json}`);
+
+
+        const resourceType = json.resource_type;
+        const resourceId = json.resource_id;
+        const pricePerMonth = json.price_per_month;
+        const region = json.region;
+
+        if (typeof resourceType !== 'string') {
+            OutputChannel.getInstance().appendLine(`Could not parse the resource type ${resourceType}`);
+            return undefined;
+        }
+
+        if (typeof resourceId !== 'string') {
+            OutputChannel.getInstance().appendLine(`Could not parse the resource id ${resourceId}`);
+            return undefined;
+        }
+
+        if (typeof region !== 'string') {
+            OutputChannel.getInstance().appendLine(`Could not parse the region ${region}`);
+            return undefined;
+        }
+
+        if (typeof pricePerMonth !== 'number') {
+            OutputChannel.getInstance().appendLine(`Could not parse the price per month ${pricePerMonth}`);
+            return undefined;
+        }
+
+
+        let resourceElement = accountCost.getResourceType(resourceType);
+        if (typeof resourceElement === 'undefined') {
+            resourceElement = {
+                globalPrice: 0,
+                values: new Map()
+            };
+        }
+
+        resourceElement.values.set(resourceId, pricePerMonth);
+        resourceElement.globalPrice += pricePerMonth;
+        accountCost.accountCost += pricePerMonth;
+        accountCost.region = region;
+        accountCost.setResourceType(resourceType, resourceElement);
+    }
+
+
+    return accountCost;
+}
+
+export async function fetchAccountCost(profile: Profile): Promise<AccountCost | undefined> {
+
+    const oscCostPath = getOscCostPath();
+
+    if (typeof oscCostPath === 'undefined') {
+        vscode.window.showErrorMessage("Cannot find osc-cost binary. Please install it.");
+        return Promise.resolve(undefined);
+    }
+
+    const res = await shell.exec(`osc-cost --format json --profile ${profile.name}`);
+    if (typeof res === "undefined") {
+        return res;
+    }
+
+    return Promise.resolve(jsonToAccountCost(res.stdout.trim()));
+}
+
+
+export function isOscCostEnabled(): boolean {
+    const isEnabled = getConfigurationParameter<boolean>(OSC_COST_PARAMETER + ".enabled");
+    if (typeof isEnabled === 'undefined') {
+        return false;
+    }
+    OutputChannel.getInstance().appendLine("IsEnabled:" + isEnabled);
+    return isEnabled;
+}
+
+export function getOscCostPath(): string | undefined {
+    const userOscCostPath = getConfigurationParameter<string>(OSC_COST_PARAMETER + ".oscCostPath");
+    if (typeof userOscCostPath === 'undefined' || userOscCostPath === "") {
+        const systemOscCostPath = shell.which("osc-cost");
+        if (systemOscCostPath === null) {
+            return undefined;
+        }
+        OutputChannel.getInstance().appendLine(systemOscCostPath);
+        return systemOscCostPath;
+    }
+    // Check exist
+    if (! pathExists(userOscCostPath)) {
+        return undefined;
+    }
+    OutputChannel.getInstance().appendLine(userOscCostPath);
+    return userOscCostPath;
+}
\ No newline at end of file
diff --git a/src/components/shell.ts b/src/components/shell.ts
new file mode 100644
index 0000000..99559c6
--- /dev/null
+++ b/src/components/shell.ts
@@ -0,0 +1,131 @@
+'use strict';
+
+import * as vscode from 'vscode';
+import * as shelljs from 'shelljs';
+import { ChildProcess } from 'child_process';
+
+export enum Platform {
+    // eslint-disable-next-line @typescript-eslint/naming-convention
+    Windows,
+    // eslint-disable-next-line @typescript-eslint/naming-convention
+    MacOS,
+    // eslint-disable-next-line @typescript-eslint/naming-convention
+    Linux,
+    // eslint-disable-next-line @typescript-eslint/naming-convention
+    Unsupported,  // shouldn't happen!
+}
+
+export interface Shell {
+    isWindows(): boolean;
+    isUnix(): boolean;
+    platform(): Platform;
+    execOpts(): any;
+    exec(cmd: string, stdin?: string): Promise<ShellResult | undefined>;
+    which(bin: string): string | null;
+}
+
+export const shell: Shell = {
+    isWindows: isWindows,
+    isUnix: isUnix,
+    platform: platform,
+    execOpts: execOpts,
+    exec: exec,
+    which: which,
+};
+
+const WINDOWS = 'win32';
+
+export interface ShellResult {
+    readonly code: number;
+    readonly stdout: string;
+    readonly stderr: string;
+}
+
+export type ShellHandler = (code: number, stdout: string, stderr: string) => void;
+
+function isWindows(): boolean {
+    return (process.platform === WINDOWS);
+}
+
+function isUnix(): boolean {
+    return !isWindows();
+}
+
+function platform(): Platform {
+    switch (process.platform) {
+        case 'win32': return Platform.Windows;
+        case 'darwin': return Platform.MacOS;
+        case 'linux': return Platform.Linux;
+        default: return Platform.Unsupported;
+    }
+}
+
+function concatIfSafe(homeDrive: string | undefined, homePath: string | undefined): string | undefined {
+    if (homeDrive && homePath) {
+        const safe = !homePath.toLowerCase().startsWith('\\windows\\system32');
+        if (safe) {
+            return homeDrive.concat(homePath);
+        }
+    }
+
+    return undefined;
+}
+
+function home(): string {
+    return process.env['HOME'] ||
+        concatIfSafe(process.env['HOMEDRIVE'], process.env['HOMEPATH']) ||
+        process.env['USERPROFILE'] ||
+        '';
+}
+
+function execOpts(): any {
+    let env = process.env;
+    if (isWindows()) {
+        // eslint-disable-next-line @typescript-eslint/naming-convention
+        env = Object.assign({}, env, { HOME: home() });
+    }
+    env = shellEnvironment(env);
+
+    const opts = {
+        cwd: typeof vscode.workspace.workspaceFolders === 'undefined' ? undefined : vscode.workspace.workspaceFolders[0],
+        env: env,
+        async: true
+    };
+    return opts;
+}
+
+async function exec(cmd: string, stdin?: string): Promise<ShellResult | undefined> {
+    try {
+        return await execCore(cmd, execOpts(), null, stdin);
+    } catch (ex) {
+        vscode.window.showErrorMessage(`${ex}`);
+        return undefined;
+    }
+}
+
+function execCore(cmd: string, opts: any, callback?: ((proc: ChildProcess) => void) | null, stdin?: string): Promise<ShellResult> {
+    return new Promise<ShellResult>((resolve) => {
+        const proc = shelljs.exec(cmd, opts, (code, stdout, stderr) => resolve({ code: code, stdout: stdout, stderr: stderr }));
+        if (stdin && proc.stdin !== null) {
+            proc.stdin.end(stdin);
+        }
+        if (callback) {
+            callback(proc);
+        }
+    });
+}
+
+function which(bin: string): string | null {
+    return shelljs.which(bin);
+}
+
+export function shellEnvironment(baseEnvironment: any): any {
+    const env = Object.assign({}, baseEnvironment);
+    return env;
+}
+
+const SAFE_CHARS_REGEX = /^[-,._+:@%/\w]*$/;
+
+export function isSafe(s: string): boolean {
+    return SAFE_CHARS_REGEX.test(s);
+}
diff --git a/src/configuration/utils.ts b/src/configuration/utils.ts
index 932f53c..401887f 100644
--- a/src/configuration/utils.ts
+++ b/src/configuration/utils.ts
@@ -5,6 +5,7 @@ const CONFIGURATION_NAME = "osc-viewer";
 
 export const FILTERS_PARAMETER = "filters";
 export const DISABLE_FOLDER_PARAMETER = "disableFolders";
+export const OSC_COST_PARAMETER = "costEstimation";
 
 export function getConfigurationParameter<T>(parameter: string): T | undefined {
     const conf = vscode.workspace.getConfiguration(CONFIGURATION_NAME);
diff --git a/src/explorer.ts b/src/explorer.ts
index c3e66c5..749e4c4 100644
--- a/src/explorer.ts
+++ b/src/explorer.ts
@@ -1,7 +1,9 @@
 import * as vscode from 'vscode';
-import { ExplorerNode } from './flat/node';
+import { ExplorerNode, Profile } from './flat/node';
 import { ProfileNode } from './flat/node.profile';
 import { createConfigFile, getConfigFile, getDefaultConfigFilePath, jsonToProfile, readConfigFile } from './config_file/utils';
+import { AccountCost, fetchAccountCost, isOscCostEnabled } from './components/osc_cost';
+import { OutputChannel } from './logs/output_channel';
 
 
 export class OscExplorer implements vscode.TreeDataProvider<ExplorerNode> {
@@ -14,16 +16,21 @@ export class OscExplorer implements vscode.TreeDataProvider<ExplorerNode> {
         this._onDidChangeTreeData.fire();
     }
 
-    getTreeItem(element: ExplorerNode): vscode.TreeItem {
+    getTreeItem(element: ExplorerNode): Thenable<vscode.TreeItem> {
         return element.getTreeItem();
     }
 
-    getChildren(element?: ExplorerNode): Thenable<ExplorerNode[]> {
+    async getChildren(element?: ExplorerNode): Promise<ExplorerNode[]> {
         if (element) {
             return element.getChildren();
         } else {
-            const toExplorerNode = (profileName: string, definition: any): ProfileNode => {
-                return new ProfileNode(jsonToProfile(profileName, definition));
+            const toExplorerNode = async (profileName: string, definition: any): Promise<ProfileNode> => {
+                const profile = jsonToProfile(profileName, definition);
+                if (isOscCostEnabled()) {
+                    profile.oscCost = await this.retrieveAccountCost(profile);
+                    OutputChannel.getInstance().appendLine(`Retrieve the cost for ${profile.name}: ${profile.oscCost?.accountCost}`);
+                }
+                return Promise.resolve(new ProfileNode(profile));
             };
 
             const oscConfigObject = readConfigFile();
@@ -31,7 +38,7 @@ export class OscExplorer implements vscode.TreeDataProvider<ExplorerNode> {
                 vscode.window.showErrorMessage(vscode.l10n.t('No config file found'));
                 return Promise.resolve([]);
             }
-            const explorerNodes = Object.keys(oscConfigObject).map(dep => toExplorerNode(dep, oscConfigObject[dep]));
+            const explorerNodes = await Promise.all(Object.keys(oscConfigObject).map(async (dep) => await toExplorerNode(dep, oscConfigObject[dep])));
 
             return Promise.resolve(explorerNodes);
         }
@@ -52,4 +59,9 @@ export class OscExplorer implements vscode.TreeDataProvider<ExplorerNode> {
 
     }
 
+    async retrieveAccountCost(profile: Profile): Promise<AccountCost | undefined> {
+        // TODO: Add user options
+        return fetchAccountCost(profile);
+    }
+
 }
\ No newline at end of file
diff --git a/src/flat/folders/node.folder.ts b/src/flat/folders/node.folder.ts
index 507811a..9b10608 100644
--- a/src/flat/folders/node.folder.ts
+++ b/src/flat/folders/node.folder.ts
@@ -12,6 +12,9 @@ export abstract class FolderNode implements ExplorerFolderNode {
     getTreeItem(): vscode.TreeItem {
         const treeItem = new vscode.TreeItem(this.folderName, vscode.TreeItemCollapsibleState.Collapsed);
         treeItem.contextValue = this.getContextValue();
+        if (typeof this.profile.oscCost !== 'undefined') {
+            treeItem.description = this.profile.oscCost.getResourceTypeCost(this.folderName);
+        }
         return treeItem;
     }
 
diff --git a/src/flat/node.profile.ts b/src/flat/node.profile.ts
index 825e05e..556a3f1 100644
--- a/src/flat/node.profile.ts
+++ b/src/flat/node.profile.ts
@@ -39,12 +39,15 @@ export class ProfileNode implements ExplorerProfileNode {
 
     getTreeItem(): vscode.TreeItem {
         const treeItem = new vscode.TreeItem(this.profile.name, vscode.TreeItemCollapsibleState.Collapsed);
+        if (typeof this.profile.oscCost !== 'undefined') {
+            treeItem.description = this.profile.oscCost.getAccountCost();
+        }
         treeItem.iconPath = new vscode.ThemeIcon("account");
         treeItem.contextValue = this.getContextValue();
         return treeItem;
     }
 
-    getChildren(): Thenable<ExplorerNode[]> {
+    async getChildren(): Promise<ExplorerNode[]> {
         const resources = [
             [ACCESSKEY_FOLDER_NAME, new AccessKeysFolderNode(this.profile)],
             [APIACCESSRULES_FOLDER_NAME, new ApiAccessRulesFolderNode(this.profile)],
diff --git a/src/flat/node.ts b/src/flat/node.ts
index 0ddd7f2..6f68b88 100644
--- a/src/flat/node.ts
+++ b/src/flat/node.ts
@@ -1,4 +1,5 @@
 import * as vscode from 'vscode';
+import { AccountCost } from '../components/osc_cost';
 
 export interface ExplorerNodeBase {
     getChildren(): Thenable<ExplorerNode[]>;
@@ -63,6 +64,7 @@ export class NodeImpl {
 
 export class Profile {
     accountId: string;
+    oscCost: AccountCost | undefined;
     constructor(
         public readonly name: string,
         public readonly accessKey: string,
diff --git a/src/flat/resources/node.resources.ts b/src/flat/resources/node.resources.ts
index 9e4f4bc..5199954 100644
--- a/src/flat/resources/node.resources.ts
+++ b/src/flat/resources/node.resources.ts
@@ -42,6 +42,9 @@ export class ResourceNode implements ExplorerResourceNode {
     getTreeItem(): vscode.TreeItem {
         const treeItem = new vscode.TreeItem(this.resourceId, vscode.TreeItemCollapsibleState.None);
         treeItem.description = this.resourceName;
+        if (typeof this.profile.oscCost !== 'undefined') {
+            treeItem.description += " " + this.profile.oscCost.getResourceIdCost(this.resourceType, this.resourceId);
+        }
         treeItem.iconPath = this.getIconPath();
         treeItem.command = {
             "title": vscode.l10n.t("Get"),