@waishnav/devspace 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) hide show
  1. package/README.md +146 -0
  2. package/dist/cli.js +331 -0
  3. package/dist/config.js +188 -0
  4. package/dist/db/client.js +22 -0
  5. package/dist/db/schema.js +29 -0
  6. package/dist/git-worktrees.js +134 -0
  7. package/dist/git.js +41 -0
  8. package/dist/logger.js +69 -0
  9. package/dist/oauth-provider.js +266 -0
  10. package/dist/pi-tools.js +81 -0
  11. package/dist/review-checkpoints.js +142 -0
  12. package/dist/roots.js +34 -0
  13. package/dist/server.js +1148 -0
  14. package/dist/skills.js +45 -0
  15. package/dist/ui/.vite/manifest.json +2520 -0
  16. package/dist/ui/assets/abap-CLvhMVsD.js +1 -0
  17. package/dist/ui/assets/actionscript-3--17pq3dv.js +1 -0
  18. package/dist/ui/assets/ada-C5qYipkI.js +1 -0
  19. package/dist/ui/assets/andromeeda-vGVdxbeo.js +1 -0
  20. package/dist/ui/assets/angular-html-Di31D1W0.js +1 -0
  21. package/dist/ui/assets/angular-ts-BKuSFrBS.js +1 -0
  22. package/dist/ui/assets/apache-U0d_L8uA.js +1 -0
  23. package/dist/ui/assets/apex-CGTLDQj6.js +1 -0
  24. package/dist/ui/assets/apl-DgqYbYoh.js +1 -0
  25. package/dist/ui/assets/applescript-CCn79oCD.js +1 -0
  26. package/dist/ui/assets/ara-4CJ0cIlV.js +1 -0
  27. package/dist/ui/assets/asciidoc-DE70LPWp.js +1 -0
  28. package/dist/ui/assets/asm-Cmm7eHzH.js +1 -0
  29. package/dist/ui/assets/astro-B19gi6Os.js +1 -0
  30. package/dist/ui/assets/aurora-x-CDeNXAV0.js +1 -0
  31. package/dist/ui/assets/awk-BWXHIvNe.js +1 -0
  32. package/dist/ui/assets/ayu-dark-DluEY0Gj.js +1 -0
  33. package/dist/ui/assets/ayu-light-C3h-C4tm.js +1 -0
  34. package/dist/ui/assets/ayu-mirage-Bqwy1Gya.js +1 -0
  35. package/dist/ui/assets/ballerina-B7ZEbQpA.js +1 -0
  36. package/dist/ui/assets/bat-Bo4NYOV-.js +1 -0
  37. package/dist/ui/assets/beancount-D-usSTwE.js +1 -0
  38. package/dist/ui/assets/berry-DKpUyyne.js +1 -0
  39. package/dist/ui/assets/bibtex-Ci_nEsc7.js +1 -0
  40. package/dist/ui/assets/bicep-CUHmPFLl.js +1 -0
  41. package/dist/ui/assets/bird2-C2hNVINV.js +1 -0
  42. package/dist/ui/assets/blade-BKHjA4oS.js +1 -0
  43. package/dist/ui/assets/bsl-BkkzgIyY.js +1 -0
  44. package/dist/ui/assets/c-FjyGimBn.js +1 -0
  45. package/dist/ui/assets/c3-CnJL0r0V.js +1 -0
  46. package/dist/ui/assets/cadence-CQ2zXKGN.js +1 -0
  47. package/dist/ui/assets/cairo-DLTphjLi.js +1 -0
  48. package/dist/ui/assets/catppuccin-frappe-3VR1Za6u.js +1 -0
  49. package/dist/ui/assets/catppuccin-latte-DwIHMF0Q.js +1 -0
  50. package/dist/ui/assets/catppuccin-macchiato-DYnBP6_5.js +1 -0
  51. package/dist/ui/assets/catppuccin-mocha-DYhrFGRu.js +1 -0
  52. package/dist/ui/assets/clarity-SemFz856.js +1 -0
  53. package/dist/ui/assets/clojure-DqKBuwfJ.js +1 -0
  54. package/dist/ui/assets/cmake-Bj61d0ZC.js +1 -0
  55. package/dist/ui/assets/cobol-DlmtgjjX.js +1 -0
  56. package/dist/ui/assets/codeowners-C8r90Shi.js +1 -0
  57. package/dist/ui/assets/codeql-oeQT6MSM.js +1 -0
  58. package/dist/ui/assets/coffee-BlTKLwcf.js +1 -0
  59. package/dist/ui/assets/common-lisp-Cv5bFMCO.js +1 -0
  60. package/dist/ui/assets/coq-BrsZFFmf.js +1 -0
  61. package/dist/ui/assets/cpp-DtVUwoaa.js +1 -0
  62. package/dist/ui/assets/crystal-C0TLGTHr.js +1 -0
  63. package/dist/ui/assets/csharp-Ct8U2NOr.js +1 -0
  64. package/dist/ui/assets/css-FssmIjiX.js +1 -0
  65. package/dist/ui/assets/csv-Dx-8-gkx.js +1 -0
  66. package/dist/ui/assets/cue-CE9AQfxI.js +1 -0
  67. package/dist/ui/assets/cypher-ClKdZ_lG.js +1 -0
  68. package/dist/ui/assets/d-qD-0Kul2.js +1 -0
  69. package/dist/ui/assets/dark-plus-Cs2F2srj.js +1 -0
  70. package/dist/ui/assets/dart-DkHntEIa.js +1 -0
  71. package/dist/ui/assets/dax-BkyTk9wS.js +1 -0
  72. package/dist/ui/assets/desktop-Dlh5hvp9.js +1 -0
  73. package/dist/ui/assets/diff-woXpYk--.js +1 -0
  74. package/dist/ui/assets/docker-IyjqRm3v.js +1 -0
  75. package/dist/ui/assets/dotenv-_5a1GRtc.js +1 -0
  76. package/dist/ui/assets/dracula-BHWKrbxM.js +1 -0
  77. package/dist/ui/assets/dracula-soft-5eyTD99u.js +1 -0
  78. package/dist/ui/assets/dream-maker-DW3nJb8Q.js +1 -0
  79. package/dist/ui/assets/edge-_m-12TBz.js +1 -0
  80. package/dist/ui/assets/elixir-RKJED3b7.js +1 -0
  81. package/dist/ui/assets/elm-CzMSD9Oq.js +1 -0
  82. package/dist/ui/assets/emacs-lisp-C9PiwqqW.js +1 -0
  83. package/dist/ui/assets/erb-Cqpp-3vK.js +1 -0
  84. package/dist/ui/assets/erlang-Cphh6RMH.js +1 -0
  85. package/dist/ui/assets/everforest-dark-sB-x3p7T.js +1 -0
  86. package/dist/ui/assets/everforest-light-Df2xbC6M.js +1 -0
  87. package/dist/ui/assets/fennel-DQxkIbk2.js +1 -0
  88. package/dist/ui/assets/fish-BJitypiv.js +1 -0
  89. package/dist/ui/assets/fluent-C03EYrpw.js +1 -0
  90. package/dist/ui/assets/fortran-fixed-form-DEKoE2YW.js +1 -0
  91. package/dist/ui/assets/fortran-free-form-CYNrtFtB.js +1 -0
  92. package/dist/ui/assets/fsharp-D13ZGOAj.js +1 -0
  93. package/dist/ui/assets/gdresource-C0sCabJj.js +1 -0
  94. package/dist/ui/assets/gdscript-Cp2uCuqX.js +1 -0
  95. package/dist/ui/assets/gdshader-CBce3t8t.js +1 -0
  96. package/dist/ui/assets/genie-CV2tkWYe.js +1 -0
  97. package/dist/ui/assets/gherkin-DExj1W_8.js +1 -0
  98. package/dist/ui/assets/git-commit-BSykSTBG.js +1 -0
  99. package/dist/ui/assets/git-rebase-DLS2r2oj.js +1 -0
  100. package/dist/ui/assets/github-dark-C-LZuMrd.js +1 -0
  101. package/dist/ui/assets/github-dark-default-DXG-b-1a.js +1 -0
  102. package/dist/ui/assets/github-dark-dimmed-Bx1FflLF.js +1 -0
  103. package/dist/ui/assets/github-dark-high-contrast-B_tTalzw.js +1 -0
  104. package/dist/ui/assets/github-light-EUqPIrTm.js +1 -0
  105. package/dist/ui/assets/github-light-default-BXViO-2h.js +1 -0
  106. package/dist/ui/assets/github-light-high-contrast-B68TUdTA.js +1 -0
  107. package/dist/ui/assets/gleam-CSRkHgEL.js +1 -0
  108. package/dist/ui/assets/glimmer-js-B1t-JGK1.js +1 -0
  109. package/dist/ui/assets/glimmer-ts-CazygCNf.js +1 -0
  110. package/dist/ui/assets/glsl-gBg2vKZ-.js +1 -0
  111. package/dist/ui/assets/gn-ilITqXS6.js +1 -0
  112. package/dist/ui/assets/gnuplot-7GGW24-e.js +1 -0
  113. package/dist/ui/assets/go-BJwz_mda.js +1 -0
  114. package/dist/ui/assets/graphql-C8u6MNtl.js +1 -0
  115. package/dist/ui/assets/groovy-CacY0gHj.js +1 -0
  116. package/dist/ui/assets/gruvbox-dark-hard-C820rvS2.js +1 -0
  117. package/dist/ui/assets/gruvbox-dark-medium-BPjhmG05.js +1 -0
  118. package/dist/ui/assets/gruvbox-dark-soft-MrdJrrXF.js +1 -0
  119. package/dist/ui/assets/gruvbox-light-hard-BC_s9l72.js +1 -0
  120. package/dist/ui/assets/gruvbox-light-medium-BAWPOn9u.js +1 -0
  121. package/dist/ui/assets/gruvbox-light-soft-BSMLrYjP.js +1 -0
  122. package/dist/ui/assets/hack-CgKuqejW.js +1 -0
  123. package/dist/ui/assets/haml-I5WU4_Rg.js +1 -0
  124. package/dist/ui/assets/handlebars-DGf6O3Q6.js +1 -0
  125. package/dist/ui/assets/haskell-D8IpX4py.js +1 -0
  126. package/dist/ui/assets/haxe-OTjmBuCE.js +1 -0
  127. package/dist/ui/assets/hcl-Dh228itO.js +1 -0
  128. package/dist/ui/assets/heavy-payload-Bp6srDbj.js +4 -0
  129. package/dist/ui/assets/hjson-CxZEssPk.js +1 -0
  130. package/dist/ui/assets/hlsl-Cvrh5tZx.js +1 -0
  131. package/dist/ui/assets/horizon-CE9ld1lL.js +1 -0
  132. package/dist/ui/assets/horizon-bright-Br1oVSNq.js +1 -0
  133. package/dist/ui/assets/houston-CsvMBhTu.js +1 -0
  134. package/dist/ui/assets/html-BrIuweS5.js +1 -0
  135. package/dist/ui/assets/html-derivative-CflP_1S6.js +1 -0
  136. package/dist/ui/assets/http-qgGkv9Ds.js +1 -0
  137. package/dist/ui/assets/hurl-CantyQ5z.js +1 -0
  138. package/dist/ui/assets/hxml-B0Qn7Nwc.js +1 -0
  139. package/dist/ui/assets/hy-CZbG8q4J.js +1 -0
  140. package/dist/ui/assets/imba-DsUTQ-LC.js +1 -0
  141. package/dist/ui/assets/ini-B5eOa1yu.js +1 -0
  142. package/dist/ui/assets/java-DqStxnBY.js +1 -0
  143. package/dist/ui/assets/javascript-CJ1ZUMNM.js +1 -0
  144. package/dist/ui/assets/jinja-Ta-y-8tW.js +1 -0
  145. package/dist/ui/assets/jison-DZStAtdf.js +1 -0
  146. package/dist/ui/assets/json-Bfn_pgvS.js +1 -0
  147. package/dist/ui/assets/json5-BR5RXkoi.js +1 -0
  148. package/dist/ui/assets/jsonc-CYpm1nAK.js +1 -0
  149. package/dist/ui/assets/jsonl-CmCQp5Yx.js +1 -0
  150. package/dist/ui/assets/jsonnet-CJTPZ8u_.js +1 -0
  151. package/dist/ui/assets/jssm-DXw9l8Rf.js +1 -0
  152. package/dist/ui/assets/jsx-CFi5D1JI.js +1 -0
  153. package/dist/ui/assets/julia-CmuPb_FV.js +1 -0
  154. package/dist/ui/assets/just-xoDaYyy4.js +1 -0
  155. package/dist/ui/assets/kanagawa-dragon-CXtmUGW6.js +1 -0
  156. package/dist/ui/assets/kanagawa-lotus-BN08jTvb.js +1 -0
  157. package/dist/ui/assets/kanagawa-wave-CTweb8Dz.js +1 -0
  158. package/dist/ui/assets/kdl-CsD5j6eV.js +1 -0
  159. package/dist/ui/assets/kotlin-DhhofPvG.js +1 -0
  160. package/dist/ui/assets/kusto-BUv0MjJC.js +1 -0
  161. package/dist/ui/assets/laserwave-C_8bwKvT.js +1 -0
  162. package/dist/ui/assets/latex-C7jbQT4s.js +1 -0
  163. package/dist/ui/assets/lean-CewbzKMR.js +1 -0
  164. package/dist/ui/assets/less-DVTAwKKz.js +1 -0
  165. package/dist/ui/assets/light-plus-DVQuIRkW.js +1 -0
  166. package/dist/ui/assets/liquid-DyVckOju.js +1 -0
  167. package/dist/ui/assets/llvm-Cm23YOpf.js +1 -0
  168. package/dist/ui/assets/log-BNLmms1o.js +1 -0
  169. package/dist/ui/assets/logo-Cluzi2Zq.js +1 -0
  170. package/dist/ui/assets/lua-CQGEo-kr.js +1 -0
  171. package/dist/ui/assets/luau-CNKltnaQ.js +1 -0
  172. package/dist/ui/assets/make-Dixweg8N.js +1 -0
  173. package/dist/ui/assets/markdown-BYOwaDjH.js +1 -0
  174. package/dist/ui/assets/marko-CF3FIlcL.js +1 -0
  175. package/dist/ui/assets/material-theme-Bm3Qr25_.js +1 -0
  176. package/dist/ui/assets/material-theme-darker-2IIEA8gg.js +1 -0
  177. package/dist/ui/assets/material-theme-lighter-uhdI0v04.js +1 -0
  178. package/dist/ui/assets/material-theme-ocean-CHQ94UKr.js +1 -0
  179. package/dist/ui/assets/material-theme-palenight-B5W6OYN7.js +1 -0
  180. package/dist/ui/assets/matlab-D7qyCx1q.js +1 -0
  181. package/dist/ui/assets/mdc-DJfBh8KU.js +1 -0
  182. package/dist/ui/assets/mdx-DQZ5AkYe.js +1 -0
  183. package/dist/ui/assets/mermaid-Bk4SNUv9.js +1 -0
  184. package/dist/ui/assets/min-dark-BSWPekZh.js +1 -0
  185. package/dist/ui/assets/min-light-DDpmG2fV.js +1 -0
  186. package/dist/ui/assets/mipsasm-BMqwQI7S.js +1 -0
  187. package/dist/ui/assets/mojo-BgCJLMeH.js +1 -0
  188. package/dist/ui/assets/monokai-CdkpiU2Y.js +1 -0
  189. package/dist/ui/assets/moonbit-CaWjb8XO.js +1 -0
  190. package/dist/ui/assets/move-B1IS1UjX.js +1 -0
  191. package/dist/ui/assets/narrat-_X_XdTYD.js +1 -0
  192. package/dist/ui/assets/nextflow-Bbiyy34d.js +1 -0
  193. package/dist/ui/assets/nextflow-groovy-Dc_ddanL.js +1 -0
  194. package/dist/ui/assets/nginx-CmN5T-d3.js +1 -0
  195. package/dist/ui/assets/night-owl-DhmEMT88.js +1 -0
  196. package/dist/ui/assets/night-owl-light-eJ-hLW7d.js +1 -0
  197. package/dist/ui/assets/nim-a_705mqZ.js +1 -0
  198. package/dist/ui/assets/nix-IvuFDN5E.js +1 -0
  199. package/dist/ui/assets/nord-Cb4Vim4T.js +1 -0
  200. package/dist/ui/assets/nushell-DcLAeLz5.js +1 -0
  201. package/dist/ui/assets/objective-c-D1A_Heim.js +1 -0
  202. package/dist/ui/assets/objective-cpp-BsSzOQcm.js +1 -0
  203. package/dist/ui/assets/ocaml-O90oeIOV.js +1 -0
  204. package/dist/ui/assets/odin-B1RWQWA5.js +1 -0
  205. package/dist/ui/assets/one-dark-pro-CLwyXe_n.js +1 -0
  206. package/dist/ui/assets/one-light-D7Lr4KcI.js +1 -0
  207. package/dist/ui/assets/openscad-BUDT5pXO.js +1 -0
  208. package/dist/ui/assets/pascal-4ZHwLPI5.js +1 -0
  209. package/dist/ui/assets/perl-BFxFi55O.js +1 -0
  210. package/dist/ui/assets/php-C9Uf0Vo_.js +1 -0
  211. package/dist/ui/assets/pierre-dark-sU4Zdns8.js +1 -0
  212. package/dist/ui/assets/pierre-dark-soft-HXgun5vs.js +1 -0
  213. package/dist/ui/assets/pierre-light-DWBk51d8.js +1 -0
  214. package/dist/ui/assets/pierre-light-soft-CodEzPxf.js +1 -0
  215. package/dist/ui/assets/pkl-ot-7Btpt.js +1 -0
  216. package/dist/ui/assets/plastic-DQwYfKfQ.js +1 -0
  217. package/dist/ui/assets/plsql-DGHpHOYJ.js +1 -0
  218. package/dist/ui/assets/po-BiJDBrnU.js +1 -0
  219. package/dist/ui/assets/poimandres-DRFjx7u4.js +1 -0
  220. package/dist/ui/assets/polar-C7UOKdEL.js +1 -0
  221. package/dist/ui/assets/postcss-BXeXVLqQ.js +1 -0
  222. package/dist/ui/assets/powerquery-DNMTfnFr.js +1 -0
  223. package/dist/ui/assets/powershell-DshXNtvi.js +1 -0
  224. package/dist/ui/assets/prisma-BsRQq5mF.js +1 -0
  225. package/dist/ui/assets/prolog-iXnhIJG7.js +1 -0
  226. package/dist/ui/assets/proto-DB4EqR-F.js +1 -0
  227. package/dist/ui/assets/pug-DQIrtlYh.js +1 -0
  228. package/dist/ui/assets/puppet-CDv2pdJW.js +1 -0
  229. package/dist/ui/assets/purescript-9MfHhQsQ.js +1 -0
  230. package/dist/ui/assets/python-gzcpVVnB.js +1 -0
  231. package/dist/ui/assets/qml-CpI_Asuw.js +1 -0
  232. package/dist/ui/assets/qmldir-DCQb3MpD.js +1 -0
  233. package/dist/ui/assets/qss-Fe1Jh2GI.js +1 -0
  234. package/dist/ui/assets/r-hYZdyIMH.js +1 -0
  235. package/dist/ui/assets/racket-DcIDlBhZ.js +1 -0
  236. package/dist/ui/assets/raku-B3gFvitq.js +1 -0
  237. package/dist/ui/assets/razor-CbXx350T.js +1 -0
  238. package/dist/ui/assets/red-CJ3rzSJv.js +1 -0
  239. package/dist/ui/assets/reg-CRGYupPL.js +1 -0
  240. package/dist/ui/assets/regexp-BdfO5R2u.js +1 -0
  241. package/dist/ui/assets/rel-BtDbiS_P.js +1 -0
  242. package/dist/ui/assets/review-payload-CC-3-Lb9.js +1 -0
  243. package/dist/ui/assets/riscv-Ckw8ddFX.js +1 -0
  244. package/dist/ui/assets/ron-VUp2lXgN.js +1 -0
  245. package/dist/ui/assets/rose-pine-BthvhNj6.js +1 -0
  246. package/dist/ui/assets/rose-pine-dawn-Dg85fqjY.js +1 -0
  247. package/dist/ui/assets/rose-pine-moon-hon4tzzS.js +1 -0
  248. package/dist/ui/assets/rosmsg-CAekHB0j.js +1 -0
  249. package/dist/ui/assets/rst-CP6mAm3Y.js +1 -0
  250. package/dist/ui/assets/ruby-8tjXzrRr.js +1 -0
  251. package/dist/ui/assets/rust-Cfkwpbl8.js +1 -0
  252. package/dist/ui/assets/sas-rqWHY37U.js +1 -0
  253. package/dist/ui/assets/sass-DXrisJhu.js +1 -0
  254. package/dist/ui/assets/scala-DKOlJaKm.js +1 -0
  255. package/dist/ui/assets/scheme-DQCgrYNe.js +1 -0
  256. package/dist/ui/assets/scss-aGYgGui9.js +1 -0
  257. package/dist/ui/assets/sdbl-bTVj8UrX.js +1 -0
  258. package/dist/ui/assets/shaderlab-TOUzSsQk.js +1 -0
  259. package/dist/ui/assets/shellscript-CYr5JWBI.js +1 -0
  260. package/dist/ui/assets/shellsession-CO3ljRR7.js +1 -0
  261. package/dist/ui/assets/slack-dark-DnToyrRv.js +1 -0
  262. package/dist/ui/assets/slack-ochin-B2OO5cIa.js +1 -0
  263. package/dist/ui/assets/smalltalk-B16xEiuN.js +1 -0
  264. package/dist/ui/assets/snazzy-light-4G7pJPwS.js +1 -0
  265. package/dist/ui/assets/solarized-dark-DV17i1UV.js +1 -0
  266. package/dist/ui/assets/solarized-light-DSh2HLQt.js +1 -0
  267. package/dist/ui/assets/solidity-CKzVLygQ.js +1 -0
  268. package/dist/ui/assets/soy-C4_rLmHV.js +1 -0
  269. package/dist/ui/assets/sparql-D_iOobhT.js +1 -0
  270. package/dist/ui/assets/splunk-BC2Px7Mm.js +1 -0
  271. package/dist/ui/assets/sql-2jcbKHJ9.js +1 -0
  272. package/dist/ui/assets/ssh-config-BgfXC-Er.js +1 -0
  273. package/dist/ui/assets/stata-Dbr0lM_v.js +1 -0
  274. package/dist/ui/assets/stylus-B6D30XZt.js +1 -0
  275. package/dist/ui/assets/surrealql-Cp0eMxMo.js +1 -0
  276. package/dist/ui/assets/svelte-BfsT9lcS.js +1 -0
  277. package/dist/ui/assets/swift-DonLKvLd.js +1 -0
  278. package/dist/ui/assets/synthwave-84-nFMaYfgc.js +1 -0
  279. package/dist/ui/assets/system-verilog-DJ5XKQeo.js +1 -0
  280. package/dist/ui/assets/systemd-BxMlprV5.js +1 -0
  281. package/dist/ui/assets/talonscript-CohzipZa.js +1 -0
  282. package/dist/ui/assets/tasl-DMoTqEGO.js +1 -0
  283. package/dist/ui/assets/tcl-CZd0xW_V.js +1 -0
  284. package/dist/ui/assets/templ-BBOwNqeW.js +1 -0
  285. package/dist/ui/assets/terraform-DswuEJGm.js +1 -0
  286. package/dist/ui/assets/tex-CPmn_RsX.js +1 -0
  287. package/dist/ui/assets/tokyo-night-oM2G3aXe.js +1 -0
  288. package/dist/ui/assets/toml-CcmNWLt0.js +1 -0
  289. package/dist/ui/assets/ts-tags-DMILlUz_.js +1 -0
  290. package/dist/ui/assets/tsv-sltzmVWM.js +1 -0
  291. package/dist/ui/assets/tsx-CUP2Lfiz.js +1 -0
  292. package/dist/ui/assets/turtle-ByJddavk.js +1 -0
  293. package/dist/ui/assets/twig-DEZ_7SDX.js +1 -0
  294. package/dist/ui/assets/typescript-DhaMQEhQ.js +1 -0
  295. package/dist/ui/assets/typespec-B88KGewJ.js +1 -0
  296. package/dist/ui/assets/typst-DI99ib-x.js +1 -0
  297. package/dist/ui/assets/useFileDiffInstance-Bo6irrE6.js +244 -0
  298. package/dist/ui/assets/v-DETTlOr0.js +1 -0
  299. package/dist/ui/assets/vala-zf12oZj6.js +1 -0
  300. package/dist/ui/assets/vb-Djn5o6TS.js +1 -0
  301. package/dist/ui/assets/verilog-CiiDBU1e.js +1 -0
  302. package/dist/ui/assets/vesper-D5bVUKB1.js +1 -0
  303. package/dist/ui/assets/vhdl-BroJfC0k.js +1 -0
  304. package/dist/ui/assets/viml-DvXPmvsu.js +1 -0
  305. package/dist/ui/assets/vitesse-black-fwtXNY1n.js +1 -0
  306. package/dist/ui/assets/vitesse-dark-BZCL-v6S.js +1 -0
  307. package/dist/ui/assets/vitesse-light-VbXTXTou.js +1 -0
  308. package/dist/ui/assets/vue-CAaS6wtt.js +1 -0
  309. package/dist/ui/assets/vue-html-D3Etensv.js +1 -0
  310. package/dist/ui/assets/vue-vine-DNRKj0Lh.js +1 -0
  311. package/dist/ui/assets/vyper-CgoNMtux.js +1 -0
  312. package/dist/ui/assets/wasm-BnjxR4X6.js +1 -0
  313. package/dist/ui/assets/wasm-ByWQv1Qj.js +1 -0
  314. package/dist/ui/assets/wenyan-C8pVoKbM.js +1 -0
  315. package/dist/ui/assets/wgsl-BsKzXJz4.js +1 -0
  316. package/dist/ui/assets/wikitext-ClFFjSW2.js +1 -0
  317. package/dist/ui/assets/wit-DdvCle-K.js +1 -0
  318. package/dist/ui/assets/wolfram-DLL8P-h_.js +1 -0
  319. package/dist/ui/assets/workspace-app-8--oTbCd.css +1 -0
  320. package/dist/ui/assets/workspace-app-BLeU1qC_.js +118 -0
  321. package/dist/ui/assets/xml-M-X6I2aP.js +1 -0
  322. package/dist/ui/assets/xsl-CR0ZlrL7.js +1 -0
  323. package/dist/ui/assets/yaml-pI4xDDgj.js +1 -0
  324. package/dist/ui/assets/zenscript-BnlCZFoB.js +1 -0
  325. package/dist/ui/assets/zig-CMLA9XwU.js +1 -0
  326. package/dist/ui/workspace-app.html +15 -0
  327. package/dist/user-config.js +57 -0
  328. package/dist/workspace-store.js +125 -0
  329. package/dist/workspaces.js +226 -0
  330. package/docs/assets/devspace-logo-light.png +0 -0
  331. package/docs/assets/devspace-screenshot.png +0 -0
  332. package/docs/chatgpt-coding-workflow.md +143 -0
  333. package/docs/configuration.md +129 -0
  334. package/docs/gotchas.md +214 -0
  335. package/docs/security.md +100 -0
  336. package/docs/setup.md +132 -0
  337. package/package.json +66 -0
  338. package/scripts/build-release.mjs +89 -0
  339. package/scripts/ensure-native-deps.mjs +29 -0
package/README.md ADDED
@@ -0,0 +1,146 @@
1
+ <p align="center">
2
+ <picture>
3
+ <img src="docs/assets/devspace-logo-light.png" alt="DevSpace logo" width="140">
4
+ </picture>
5
+ </p>
6
+
7
+ <h1 align="center">DevSpace</h1>
8
+
9
+ <p align="center">Bring a Codex-style coding workflow to ChatGPT.</p>
10
+
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/@waishnav/devspace"><img alt="npm" src="https://img.shields.io/npm/v/%40waishnav%2Fdevspace?style=flat-square" /></a>
13
+ <a href="https://github.com/Waishnav/devspace/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/Waishnav/devspace/ci.yml?style=flat-square&branch=main" /></a>
14
+ <a href="https://github.com/Waishnav/devspace/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/npm/l/%40waishnav%2Fdevspace?style=flat-square" /></a>
15
+ </p>
16
+
17
+ [![DevSpace connected to ChatGPT](docs/assets/devspace-screenshot.png)](docs/assets/devspace-screenshot.png)
18
+
19
+ **Give ChatGPT a secure connection to your own machine and Turn ChatGPT into Codex**
20
+
21
+ DevSpace is a self-hosted MCP server that lets ChatGPT read, edit, search, and run code in your real local projects — your files, your tools, your terminal — without uploading anything to a third party. You run it on your machine, expose it through a tunnel you control, and approve the connection with a password only you have.
22
+
23
+ ## Quick Start
24
+
25
+ DevSpace requires Node `>=20.12 <27`. Node 22 LTS is recommended.
26
+
27
+ ```bash
28
+ npx @waishnav/devspace init
29
+ npx @waishnav/devspace serve
30
+ ```
31
+
32
+ During setup, DevSpace asks for:
33
+
34
+ - the local project folders ChatGPT is allowed to open through DevSpace
35
+ - the local port, usually `7676`
36
+ - your public HTTPS base URL from Cloudflare Tunnel, ngrok, Pinggy, Tailscale Funnel, or
37
+ another reverse proxy
38
+
39
+ Use the public origin without `/mcp` during setup:
40
+
41
+ ```text
42
+ https://your-tunnel-host.example.com
43
+ ```
44
+
45
+ Then configure your MCP client with:
46
+
47
+ ```text
48
+ https://your-tunnel-host.example.com/mcp
49
+ ```
50
+
51
+ When the client connects, DevSpace opens an Owner password approval page. Enter
52
+ the Owner password printed by `devspace init`. It is also stored in:
53
+
54
+ ```text
55
+ ~/.devspace/auth.json
56
+ ```
57
+
58
+ Keep that password private.
59
+
60
+ ## What ChatGPT Gets
61
+
62
+ After the MCP client connects, ChatGPT can open a project with
63
+ `open_workspace` and then reuse the returned `workspaceId` for later calls.
64
+
65
+ DevSpace provides tools for:
66
+
67
+ - reading, writing, and editing files inside the opened workspace
68
+ - searching files and listing directories
69
+ - running shell commands for tests, builds, git, and package scripts
70
+ - opening isolated Git worktrees when you want parallel work
71
+ - loading `AGENTS.md` and `CLAUDE.md` instructions
72
+ - exposing local agent skills from your skill folders
73
+ - showing ChatGPT Apps review cards for aggregate diffs
74
+
75
+ The default local endpoint is:
76
+
77
+ ```text
78
+ http://127.0.0.1:7676/mcp
79
+ ```
80
+
81
+ Most users should connect through a public HTTPS tunnel:
82
+
83
+ ```text
84
+ https://your-tunnel-host.example.com/mcp
85
+ ```
86
+
87
+ ## Mental Model
88
+
89
+ DevSpace is remote access to selected local folders.
90
+
91
+ You decide which roots are allowed. The MCP client still has powerful local
92
+ capabilities inside an opened workspace, including shell execution. Treat a
93
+ connected client like a trusted coding partner with access to your machine.
94
+
95
+ For a normal ChatGPT coding session:
96
+
97
+ 1. Start your tunnel.
98
+ 2. Run `npx @waishnav/devspace serve`.
99
+ 3. Connect the MCP client to your public `/mcp` URL.
100
+ 4. Approve the connection with the Owner password.
101
+ 5. Ask ChatGPT to open a project inside one of your allowed roots.
102
+
103
+ ## Platform Support
104
+
105
+ DevSpace supports Linux, macOS, and Windows environments with a Bash-compatible
106
+ shell.
107
+
108
+ | Platform | Status | Notes |
109
+ | ------------------------------------------------- | ----------------- | ---------------------------------------------- |
110
+ | Linux | Supported | Requires Node, npm, Git, and Bash. |
111
+ | macOS | Supported | Requires Node, npm, Git, and Bash. |
112
+ | Windows with Git Bash, WSL, MSYS2, or Cygwin Bash | Supported | Git Bash is the simplest native Windows setup. |
113
+ | Windows PowerShell or `cmd.exe` only | Not supported yet | Install Git Bash or use WSL. |
114
+
115
+ Run this to inspect your local setup:
116
+
117
+ ```bash
118
+ npx @waishnav/devspace doctor
119
+ ```
120
+
121
+ ## Documentation
122
+
123
+ - [Setup Guide](docs/setup.md)
124
+ - [ChatGPT Coding Workflow](docs/chatgpt-coding-workflow.md)
125
+ - [Configuration Reference](docs/configuration.md)
126
+ - [Security Model](docs/security.md)
127
+ - [Troubleshooting Gotchas](docs/gotchas.md)
128
+
129
+ ## Local Development
130
+
131
+ For working on DevSpace itself:
132
+
133
+ ```bash
134
+ npm install --include=dev
135
+ npm run typecheck
136
+ npm test
137
+ npm run build
138
+ npm run start
139
+ ```
140
+
141
+ For long-running local server processes, build an immutable release copy:
142
+
143
+ ```bash
144
+ npm run release:build
145
+ npm run release:start
146
+ ```
package/dist/cli.js ADDED
@@ -0,0 +1,331 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from "node:module";
3
+ import { stdin as input, stdout as output } from "node:process";
4
+ import { resolve } from "node:path";
5
+ import * as prompts from "@clack/prompts";
6
+ import { getShellConfig } from "@earendil-works/pi-coding-agent";
7
+ import { satisfies } from "semver";
8
+ import { loadConfig } from "./config.js";
9
+ import { generateOwnerToken, loadDevspaceFiles, writeDevspaceAuth, writeDevspaceConfig, } from "./user-config.js";
10
+ import { expandHomePath } from "./roots.js";
11
+ const require = createRequire(import.meta.url);
12
+ const SUPPORTED_NODE_RANGE = ">=20.12 <27";
13
+ async function main(argv) {
14
+ assertSupportedNode();
15
+ const [rawCommand, ...args] = argv;
16
+ const command = normalizeCommand(rawCommand);
17
+ switch (command) {
18
+ case "serve":
19
+ await ensureConfigured();
20
+ await serve();
21
+ return;
22
+ case "init":
23
+ await runInit({ force: args.includes("--force") });
24
+ return;
25
+ case "doctor":
26
+ await runDoctor();
27
+ return;
28
+ case "config":
29
+ runConfigCommand(args);
30
+ return;
31
+ case "help":
32
+ printHelp();
33
+ return;
34
+ }
35
+ }
36
+ function normalizeCommand(command) {
37
+ if (!command || command === "serve" || command === "start")
38
+ return "serve";
39
+ if (command === "init" || command === "doctor" || command === "config")
40
+ return command;
41
+ if (command === "help" || command === "--help" || command === "-h")
42
+ return "help";
43
+ throw new Error(`Unknown command: ${command}`);
44
+ }
45
+ async function ensureConfigured() {
46
+ const files = loadDevspaceFiles();
47
+ if (files.configExists && files.authExists)
48
+ return;
49
+ if (process.env.DEVSPACE_OAUTH_OWNER_TOKEN)
50
+ return;
51
+ if (!input.isTTY || !output.isTTY) {
52
+ throw new Error([
53
+ "DevSpace is not configured and this terminal is non-interactive.",
54
+ "",
55
+ "Run:",
56
+ " devspace init",
57
+ "",
58
+ "Or provide DEVSPACE_OAUTH_OWNER_TOKEN and DEVSPACE_ALLOWED_ROOTS.",
59
+ ].join("\n"));
60
+ }
61
+ await runInit({ force: false });
62
+ }
63
+ async function runInit({ force }) {
64
+ const files = loadDevspaceFiles();
65
+ if (!force && files.configExists && files.authExists) {
66
+ prompts.log.info(`DevSpace is already configured at ${files.dir}`);
67
+ prompts.log.info("Run `devspace init --force` to update it.");
68
+ return;
69
+ }
70
+ try {
71
+ prompts.intro("DevSpace setup");
72
+ const defaultRoots = files.config.allowedRoots?.join(", ") || process.cwd();
73
+ const rootsAnswer = await textPrompt({
74
+ message: `Where are your projects located? Press Enter to use ${defaultRoots}`,
75
+ placeholder: defaultRoots,
76
+ defaultValue: defaultRoots,
77
+ validate: (value) => value?.trim() ? undefined : "Enter at least one project root.",
78
+ });
79
+ const allowedRoots = rootsAnswer
80
+ .split(",")
81
+ .map((root) => resolve(expandHomePath(root.trim())))
82
+ .filter(Boolean);
83
+ const defaultPort = String(files.config.port ?? 7676);
84
+ const portAnswer = await textPrompt({
85
+ message: `Which local port should DevSpace use? Press Enter to use ${defaultPort}`,
86
+ placeholder: defaultPort,
87
+ defaultValue: defaultPort,
88
+ validate: validatePort,
89
+ });
90
+ const port = Number(portAnswer);
91
+ prompts.note([
92
+ "DevSpace needs a public base URL so ChatGPT or Claude can reach this MCP server.",
93
+ "Create a tunnel or reverse proxy with Cloudflare Tunnel, ngrok, Pinggy, Tailscale Funnel, or your own HTTPS proxy.",
94
+ "Paste the public origin here, without /mcp.",
95
+ "",
96
+ "Example: https://your-tunnel-host.example.com",
97
+ ].join("\n"), "Public URL required");
98
+ const publicBaseUrl = normalizePublicBaseUrl(await textPrompt({
99
+ message: files.config.publicBaseUrl
100
+ ? `What is the public base URL? Press Enter to keep ${files.config.publicBaseUrl}`
101
+ : "What is the public base URL?",
102
+ placeholder: files.config.publicBaseUrl ?? "https://your-tunnel-host.example.com",
103
+ defaultValue: files.config.publicBaseUrl ?? "",
104
+ validate: validateRequiredPublicBaseUrl,
105
+ }));
106
+ const config = {
107
+ host: files.config.host ?? "127.0.0.1",
108
+ port,
109
+ allowedRoots,
110
+ publicBaseUrl,
111
+ };
112
+ const auth = {
113
+ ownerToken: files.auth.ownerToken ?? generateOwnerToken(),
114
+ };
115
+ const configPath = writeDevspaceConfig(config);
116
+ const authPath = writeDevspaceAuth(auth);
117
+ const lines = [
118
+ `Config: ${configPath}`,
119
+ `Auth: ${authPath}`,
120
+ `Local MCP URL: http://${config.host}:${config.port}/mcp`,
121
+ ...(publicBaseUrl ? [`Public MCP URL: ${publicBaseUrl}/mcp`] : []),
122
+ ];
123
+ prompts.note(lines.join("\n"), "DevSpace configured");
124
+ prompts.note([
125
+ `Owner password: ${auth.ownerToken}`,
126
+ "Use this when ChatGPT or Claude asks you to approve DevSpace access.",
127
+ `Stored at: ${authPath}`,
128
+ ].join("\n"), "Owner password");
129
+ prompts.outro("Run `devspace serve` to start the MCP server.");
130
+ }
131
+ catch (error) {
132
+ if (error instanceof SetupCancelledError) {
133
+ prompts.cancel("Setup cancelled");
134
+ return;
135
+ }
136
+ throw error;
137
+ }
138
+ }
139
+ async function serve() {
140
+ const sqliteStatus = checkSqliteNative();
141
+ if (sqliteStatus !== "ok") {
142
+ throw new Error([
143
+ "better-sqlite3 could not load for this Node runtime.",
144
+ sqliteStatus,
145
+ "",
146
+ "Try reinstalling or rebuilding dependencies under the active Node version:",
147
+ " npm rebuild better-sqlite3",
148
+ ].join("\n"));
149
+ }
150
+ const { createServer } = await import("./server.js");
151
+ const config = loadConfig();
152
+ const { app } = createServer(config);
153
+ const httpServer = app.listen(config.port, config.host, () => {
154
+ console.log(`devspace listening on http://${config.host}:${config.port}/mcp`);
155
+ console.log(`public base url: ${config.publicBaseUrl}`);
156
+ console.log(`allowed roots: ${config.allowedRoots.join(", ")}`);
157
+ console.log(`allowed hosts: ${config.allowedHosts.join(", ")}`);
158
+ if (config.allowedHosts.includes("*")) {
159
+ console.warn("warning: Host header allowlist is disabled because DEVSPACE_ALLOWED_HOSTS=*");
160
+ }
161
+ console.log("auth: Owner password approval required");
162
+ console.log(`logging: ${config.logging.level} ${config.logging.format}`);
163
+ });
164
+ const shutdown = () => {
165
+ httpServer.close(() => process.exit(0));
166
+ };
167
+ process.once("SIGINT", shutdown);
168
+ process.once("SIGTERM", shutdown);
169
+ }
170
+ async function runDoctor() {
171
+ const files = loadDevspaceFiles();
172
+ console.log(`Config dir: ${files.dir}`);
173
+ console.log(`Config file: ${files.configExists ? files.configPath : "missing"}`);
174
+ console.log(`Auth file: ${files.authExists ? files.authPath : "missing"}`);
175
+ console.log(`Node: ${process.version} (${nodeVersionStatus()})`);
176
+ console.log(`Node ABI: ${process.versions.modules}`);
177
+ console.log(`Platform: ${process.platform} ${process.arch}`);
178
+ console.log(`Git: ${checkGitAvailable()}`);
179
+ console.log(`Bash shell: ${checkBashShell()}`);
180
+ console.log(`SQLite native dependency: ${checkSqliteNative()}`);
181
+ try {
182
+ const config = loadConfig();
183
+ console.log(`Local MCP URL: http://${config.host}:${config.port}/mcp`);
184
+ console.log(`Public MCP URL: ${new URL("/mcp", config.publicBaseUrl).toString()}`);
185
+ console.log(`Allowed roots: ${config.allowedRoots.join(", ")}`);
186
+ console.log(`Allowed hosts: ${config.allowedHosts.join(", ")}`);
187
+ }
188
+ catch (error) {
189
+ console.log(`Config status: ${error instanceof Error ? error.message : String(error)}`);
190
+ }
191
+ }
192
+ function runConfigCommand(args) {
193
+ const [subcommand, key, ...rest] = args;
194
+ const files = loadDevspaceFiles();
195
+ if (!subcommand || subcommand === "get") {
196
+ console.log(JSON.stringify(files.config, null, 2));
197
+ return;
198
+ }
199
+ if (subcommand !== "set") {
200
+ throw new Error(`Unknown config command: ${subcommand}`);
201
+ }
202
+ if (key !== "publicBaseUrl") {
203
+ throw new Error("Only `devspace config set publicBaseUrl <url|null>` is supported right now.");
204
+ }
205
+ const value = rest.join(" ").trim();
206
+ if (!value) {
207
+ throw new Error("Missing publicBaseUrl value.");
208
+ }
209
+ writeDevspaceConfig({
210
+ ...files.config,
211
+ publicBaseUrl: normalizeOptionalPublicBaseUrl(value),
212
+ });
213
+ console.log(`Updated ${files.configPath}`);
214
+ }
215
+ function printHelp() {
216
+ console.log([
217
+ "DevSpace",
218
+ "",
219
+ "Usage:",
220
+ " devspace Run first-time setup if needed, then start the server",
221
+ " devspace serve Start the server",
222
+ " devspace init Create or update ~/.devspace/config.json and auth.json",
223
+ " devspace doctor Show config, runtime, and native dependency status",
224
+ " devspace config get Print persisted config",
225
+ " devspace config set publicBaseUrl <url|null>",
226
+ "",
227
+ "For temporary tunnels:",
228
+ " DEVSPACE_PUBLIC_BASE_URL=https://example.trycloudflare.com devspace serve",
229
+ ].join("\n"));
230
+ }
231
+ function normalizeOptionalPublicBaseUrl(value) {
232
+ const trimmed = value.trim();
233
+ if (!trimmed || trimmed === "null" || trimmed === "none")
234
+ return null;
235
+ return normalizePublicBaseUrl(trimmed);
236
+ }
237
+ function normalizePublicBaseUrl(value) {
238
+ const trimmed = value.trim();
239
+ const parsed = new URL(trimmed);
240
+ parsed.hash = "";
241
+ parsed.search = "";
242
+ parsed.pathname = parsed.pathname.replace(/\/+$/, "");
243
+ return parsed.toString().replace(/\/$/, "");
244
+ }
245
+ async function textPrompt(options) {
246
+ const result = await prompts.text({
247
+ ...options,
248
+ validate: (value) => options.validate?.(value?.trim() ? value : options.defaultValue),
249
+ });
250
+ if (prompts.isCancel(result))
251
+ throw new SetupCancelledError();
252
+ const value = String(result).trim();
253
+ return value || options.defaultValue;
254
+ }
255
+ function validatePort(value) {
256
+ const port = Number(value);
257
+ return Number.isInteger(port) && port >= 1 && port <= 65535
258
+ ? undefined
259
+ : "Enter a port between 1 and 65535.";
260
+ }
261
+ function validateRequiredPublicBaseUrl(value) {
262
+ const trimmed = value?.trim() ?? "";
263
+ if (!trimmed)
264
+ return "Enter the public URL from your tunnel or reverse proxy.";
265
+ if (trimmed.endsWith("/mcp"))
266
+ return "Enter the base URL only, without /mcp.";
267
+ return validatePublicBaseUrl(trimmed);
268
+ }
269
+ function validatePublicBaseUrl(value) {
270
+ try {
271
+ const parsed = new URL(value);
272
+ return parsed.protocol === "http:" || parsed.protocol === "https:"
273
+ ? undefined
274
+ : "Use an http or https URL.";
275
+ }
276
+ catch {
277
+ return "Enter a valid URL, for example https://your-tunnel-host.example.com.";
278
+ }
279
+ }
280
+ function assertSupportedNode() {
281
+ if (satisfies(process.versions.node, SUPPORTED_NODE_RANGE))
282
+ return;
283
+ throw new Error([
284
+ `DevSpace requires Node ${SUPPORTED_NODE_RANGE}.`,
285
+ `Current Node: ${process.version}`,
286
+ "",
287
+ "Install Node 22 LTS or use a version manager such as nvm, fnm, or mise.",
288
+ ].join("\n"));
289
+ }
290
+ function nodeVersionStatus() {
291
+ return satisfies(process.versions.node, SUPPORTED_NODE_RANGE)
292
+ ? `supported ${SUPPORTED_NODE_RANGE}`
293
+ : `unsupported, requires ${SUPPORTED_NODE_RANGE}`;
294
+ }
295
+ class SetupCancelledError extends Error {
296
+ }
297
+ function checkSqliteNative() {
298
+ try {
299
+ const Database = require("better-sqlite3");
300
+ const db = new Database(":memory:");
301
+ db.close();
302
+ return "ok";
303
+ }
304
+ catch (error) {
305
+ return error instanceof Error ? error.message : String(error);
306
+ }
307
+ }
308
+ function checkGitAvailable() {
309
+ try {
310
+ const { execFileSync } = require("node:child_process");
311
+ return execFileSync("git", ["--version"], { encoding: "utf8" }).trim();
312
+ }
313
+ catch (error) {
314
+ const message = error instanceof Error ? error.message : String(error);
315
+ return `unavailable (${message})`;
316
+ }
317
+ }
318
+ function checkBashShell() {
319
+ try {
320
+ const { shell, args } = getShellConfig();
321
+ return `${shell} ${args.join(" ")}`;
322
+ }
323
+ catch (error) {
324
+ const message = error instanceof Error ? error.message : String(error);
325
+ return `unavailable (${message})`;
326
+ }
327
+ }
328
+ main(process.argv.slice(2)).catch((error) => {
329
+ console.error(error instanceof Error ? error.message : String(error));
330
+ process.exitCode = 1;
331
+ });
package/dist/config.js ADDED
@@ -0,0 +1,188 @@
1
+ import { homedir } from "node:os";
2
+ import { join, resolve } from "node:path";
3
+ import { expandHomePath } from "./roots.js";
4
+ import { loadDevspaceFiles } from "./user-config.js";
5
+ const DEFAULT_OAUTH_ACCESS_TOKEN_TTL_SECONDS = 60 * 60;
6
+ const DEFAULT_OAUTH_REFRESH_TOKEN_TTL_SECONDS = 30 * 24 * 60 * 60;
7
+ function parsePort(value) {
8
+ if (value === undefined || value === "")
9
+ return 7676;
10
+ const port = Number(value);
11
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
12
+ throw new Error(`Invalid PORT: ${value}`);
13
+ }
14
+ return port;
15
+ }
16
+ function parseAllowedRoots(value) {
17
+ if (Array.isArray(value)) {
18
+ const roots = value.map((entry) => entry.trim()).filter(Boolean);
19
+ return (roots.length > 0 ? roots : [process.cwd()]).map((root) => resolve(expandHomePath(root)));
20
+ }
21
+ const rawRoots = value
22
+ ?.split(",")
23
+ .map((entry) => entry.trim())
24
+ .filter(Boolean) ?? [];
25
+ const roots = rawRoots.length > 0 ? rawRoots : [process.cwd()];
26
+ return roots.map((root) => resolve(expandHomePath(root)));
27
+ }
28
+ function parseAllowedHosts(value, derivedHosts) {
29
+ if (Array.isArray(value)) {
30
+ return normalizeAllowedHosts(value, derivedHosts);
31
+ }
32
+ const rawHosts = value
33
+ ?.split(",")
34
+ .map((entry) => entry.trim())
35
+ .filter(Boolean) ?? [];
36
+ return normalizeAllowedHosts(rawHosts, derivedHosts);
37
+ }
38
+ function normalizeAllowedHosts(rawHosts, derivedHosts) {
39
+ const hosts = rawHosts.length > 0 ? rawHosts : derivedHosts;
40
+ if (hosts.includes("*"))
41
+ return ["*"];
42
+ return Array.from(new Set(hosts.map((host) => host.trim()).filter(Boolean)));
43
+ }
44
+ function parseBoolean(value) {
45
+ return ["1", "true", "yes", "on"].includes(value?.toLowerCase() ?? "");
46
+ }
47
+ function parseMinimalTools(env) {
48
+ return env.DEVSPACE_TOOL_MODE === "minimal" || parseBoolean(env.DEVSPACE_MINIMAL_TOOLS);
49
+ }
50
+ function parseLogLevel(value) {
51
+ if (!value || value === "info")
52
+ return "info";
53
+ if (["silent", "error", "warn", "debug"].includes(value))
54
+ return value;
55
+ throw new Error(`Invalid DEVSPACE_LOG_LEVEL: ${value}`);
56
+ }
57
+ function parseLogFormat(value) {
58
+ if (!value || value === "json")
59
+ return "json";
60
+ if (value === "pretty")
61
+ return "pretty";
62
+ throw new Error(`Invalid DEVSPACE_LOG_FORMAT: ${value}`);
63
+ }
64
+ function parsePathList(value) {
65
+ return (value
66
+ ?.split(",")
67
+ .map((entry) => entry.trim())
68
+ .filter(Boolean)
69
+ .map((entry) => resolve(expandHomePath(entry))) ?? []);
70
+ }
71
+ function parseStringList(value, fallback) {
72
+ const entries = value
73
+ ?.split(",")
74
+ .map((entry) => entry.trim())
75
+ .filter(Boolean);
76
+ return entries && entries.length > 0 ? entries : fallback;
77
+ }
78
+ function parsePositiveInteger(value, fallback, name) {
79
+ if (!value)
80
+ return fallback;
81
+ const parsed = Number(value);
82
+ if (!Number.isInteger(parsed) || parsed < 1) {
83
+ throw new Error(`Invalid ${name}: ${value}`);
84
+ }
85
+ return parsed;
86
+ }
87
+ function parseToolNaming(value) {
88
+ if (!value || value === "legacy")
89
+ return "legacy";
90
+ if (value === "short")
91
+ return "short";
92
+ throw new Error(`Invalid DEVSPACE_TOOL_NAMING: ${value}`);
93
+ }
94
+ function parseLoggingConfig(env) {
95
+ return {
96
+ level: parseLogLevel(env.DEVSPACE_LOG_LEVEL),
97
+ format: parseLogFormat(env.DEVSPACE_LOG_FORMAT),
98
+ requests: env.DEVSPACE_LOG_REQUESTS === undefined ? true : parseBoolean(env.DEVSPACE_LOG_REQUESTS),
99
+ assets: parseBoolean(env.DEVSPACE_LOG_ASSETS),
100
+ toolCalls: env.DEVSPACE_LOG_TOOL_CALLS === undefined ? true : parseBoolean(env.DEVSPACE_LOG_TOOL_CALLS),
101
+ shellCommands: parseBoolean(env.DEVSPACE_LOG_SHELL_COMMANDS),
102
+ trustProxy: parseBoolean(env.DEVSPACE_TRUST_PROXY),
103
+ };
104
+ }
105
+ function parseWidgetMode(value) {
106
+ if (!value || value === "changes")
107
+ return "changes";
108
+ if (value === "off" || value === "full")
109
+ return value;
110
+ throw new Error(`Invalid DEVSPACE_WIDGETS: ${value}`);
111
+ }
112
+ function parseRequiredSecret(value, name) {
113
+ const secret = value?.trim();
114
+ if (!secret) {
115
+ throw new Error(`${name} is required for DevSpace OAuth. Run: devspace init`);
116
+ }
117
+ if (secret.length < 16) {
118
+ throw new Error(`${name} must be at least 16 characters long.`);
119
+ }
120
+ return secret;
121
+ }
122
+ function parseOAuthConfig(env, ownerToken) {
123
+ return {
124
+ ownerToken: parseRequiredSecret(env.DEVSPACE_OAUTH_OWNER_TOKEN ?? ownerToken, "DEVSPACE_OAUTH_OWNER_TOKEN"),
125
+ accessTokenTtlSeconds: parsePositiveInteger(env.DEVSPACE_OAUTH_ACCESS_TOKEN_TTL_SECONDS, DEFAULT_OAUTH_ACCESS_TOKEN_TTL_SECONDS, "DEVSPACE_OAUTH_ACCESS_TOKEN_TTL_SECONDS"),
126
+ refreshTokenTtlSeconds: parsePositiveInteger(env.DEVSPACE_OAUTH_REFRESH_TOKEN_TTL_SECONDS, DEFAULT_OAUTH_REFRESH_TOKEN_TTL_SECONDS, "DEVSPACE_OAUTH_REFRESH_TOKEN_TTL_SECONDS"),
127
+ scopes: parseStringList(env.DEVSPACE_OAUTH_SCOPES, ["devspace"]),
128
+ allowedRedirectHosts: parseStringList(env.DEVSPACE_OAUTH_ALLOWED_REDIRECT_HOSTS, [
129
+ "chatgpt.com",
130
+ "localhost",
131
+ "127.0.0.1",
132
+ ]),
133
+ };
134
+ }
135
+ function defaultStateDir() {
136
+ return join(homedir(), ".local", "share", "devspace");
137
+ }
138
+ function defaultWorktreeRoot() {
139
+ return join(homedir(), ".devspace", "worktrees");
140
+ }
141
+ function defaultAgentDir() {
142
+ return join(homedir(), ".codex");
143
+ }
144
+ export function loadConfig(env = process.env) {
145
+ const files = loadDevspaceFiles(env);
146
+ const host = env.HOST ?? files.config.host ?? "127.0.0.1";
147
+ const port = parsePort(env.PORT ?? files.config.port);
148
+ const publicBaseUrl = parsePublicBaseUrl(env.DEVSPACE_PUBLIC_BASE_URL ?? files.config.publicBaseUrl ?? localPublicBaseUrl(host, port));
149
+ const derivedAllowedHosts = [
150
+ "localhost",
151
+ "127.0.0.1",
152
+ "::1",
153
+ host,
154
+ new URL(publicBaseUrl).hostname,
155
+ ...(files.config.allowedHosts ?? []),
156
+ ];
157
+ return {
158
+ host,
159
+ port,
160
+ oauth: parseOAuthConfig(env, files.auth.ownerToken),
161
+ allowedRoots: parseAllowedRoots(env.DEVSPACE_ALLOWED_ROOTS ?? files.config.allowedRoots),
162
+ allowedHosts: parseAllowedHosts(env.DEVSPACE_ALLOWED_HOSTS, derivedAllowedHosts),
163
+ publicBaseUrl,
164
+ minimalTools: parseMinimalTools(env),
165
+ toolNaming: parseToolNaming(env.DEVSPACE_TOOL_NAMING),
166
+ widgets: parseWidgetMode(env.DEVSPACE_WIDGETS),
167
+ stateDir: resolve(expandHomePath(env.DEVSPACE_STATE_DIR ?? files.config.stateDir ?? defaultStateDir())),
168
+ worktreeRoot: resolve(expandHomePath(env.DEVSPACE_WORKTREE_ROOT ?? files.config.worktreeRoot ?? defaultWorktreeRoot())),
169
+ skillsEnabled: env.DEVSPACE_SKILLS === undefined ? true : parseBoolean(env.DEVSPACE_SKILLS),
170
+ skillPaths: parsePathList(env.DEVSPACE_SKILL_PATHS),
171
+ agentDir: resolve(expandHomePath(env.DEVSPACE_AGENT_DIR ?? files.config.agentDir ?? defaultAgentDir())),
172
+ logging: parseLoggingConfig(env),
173
+ };
174
+ }
175
+ function parsePublicBaseUrl(value) {
176
+ const parsed = new URL(value);
177
+ parsed.hash = "";
178
+ parsed.search = "";
179
+ parsed.pathname = parsed.pathname.replace(/\/+$/, "");
180
+ return parsed.toString().replace(/\/$/, "");
181
+ }
182
+ function localPublicBaseUrl(host, port) {
183
+ const publicHost = host === "0.0.0.0" || host === "::" ? "127.0.0.1" : host;
184
+ const formattedHost = publicHost.includes(":") && !publicHost.startsWith("[")
185
+ ? `[${publicHost}]`
186
+ : publicHost;
187
+ return `http://${formattedHost}:${port}`;
188
+ }
@@ -0,0 +1,22 @@
1
+ import { mkdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import Database from "better-sqlite3";
4
+ import { drizzle } from "drizzle-orm/better-sqlite3";
5
+ import * as schema from "./schema.js";
6
+ export function databasePath(stateDir) {
7
+ return join(stateDir, "devspace.sqlite");
8
+ }
9
+ export function openDatabase(stateDir) {
10
+ mkdirSync(stateDir, { recursive: true });
11
+ const sqlite = new Database(databasePath(stateDir));
12
+ sqlite.pragma("journal_mode = WAL");
13
+ sqlite.pragma("foreign_keys = ON");
14
+ return {
15
+ sqlite,
16
+ db: createDrizzleDatabase(sqlite),
17
+ close: () => sqlite.close(),
18
+ };
19
+ }
20
+ function createDrizzleDatabase(sqlite) {
21
+ return drizzle(sqlite, { schema });
22
+ }