@untangle-code/cli 0.0.0-stage → 0.1.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 (571) hide show
  1. package/LICENSE +661 -0
  2. package/NOTICE +90 -0
  3. package/README.md +424 -2
  4. package/THIRD_PARTY_LICENSES.md +152 -0
  5. package/dist/cli/args.d.ts +48 -0
  6. package/dist/cli/args.d.ts.map +1 -0
  7. package/dist/cli/args.js +167 -0
  8. package/dist/cli/args.js.map +1 -0
  9. package/dist/cli/command.d.ts +69 -0
  10. package/dist/cli/command.d.ts.map +1 -0
  11. package/dist/cli/command.js +82 -0
  12. package/dist/cli/command.js.map +1 -0
  13. package/dist/cli/deadline.d.ts +33 -0
  14. package/dist/cli/deadline.d.ts.map +1 -0
  15. package/dist/cli/deadline.js +49 -0
  16. package/dist/cli/deadline.js.map +1 -0
  17. package/dist/cli/embedder-deadline.d.ts +72 -0
  18. package/dist/cli/embedder-deadline.d.ts.map +1 -0
  19. package/dist/cli/embedder-deadline.js +117 -0
  20. package/dist/cli/embedder-deadline.js.map +1 -0
  21. package/dist/cli/exit.d.ts +71 -0
  22. package/dist/cli/exit.d.ts.map +1 -0
  23. package/dist/cli/exit.js +81 -0
  24. package/dist/cli/exit.js.map +1 -0
  25. package/dist/cli/graphs.d.ts +65 -0
  26. package/dist/cli/graphs.d.ts.map +1 -0
  27. package/dist/cli/graphs.js +108 -0
  28. package/dist/cli/graphs.js.map +1 -0
  29. package/dist/cli/index-freshness.d.ts +13 -0
  30. package/dist/cli/index-freshness.d.ts.map +1 -0
  31. package/dist/cli/index-freshness.js +226 -0
  32. package/dist/cli/index-freshness.js.map +1 -0
  33. package/dist/cli/index-refresh.d.ts +10 -0
  34. package/dist/cli/index-refresh.d.ts.map +1 -0
  35. package/dist/cli/index-refresh.js +76 -0
  36. package/dist/cli/index-refresh.js.map +1 -0
  37. package/dist/cli/index-state.d.ts +184 -0
  38. package/dist/cli/index-state.d.ts.map +1 -0
  39. package/dist/cli/index-state.js +852 -0
  40. package/dist/cli/index-state.js.map +1 -0
  41. package/dist/cli/io.d.ts +29 -0
  42. package/dist/cli/io.d.ts.map +1 -0
  43. package/dist/cli/io.js +42 -0
  44. package/dist/cli/io.js.map +1 -0
  45. package/dist/cli/language-support.d.ts +77 -0
  46. package/dist/cli/language-support.d.ts.map +1 -0
  47. package/dist/cli/language-support.js +152 -0
  48. package/dist/cli/language-support.js.map +1 -0
  49. package/dist/cli/renewing-lease.d.ts +26 -0
  50. package/dist/cli/renewing-lease.d.ts.map +1 -0
  51. package/dist/cli/renewing-lease.js +102 -0
  52. package/dist/cli/renewing-lease.js.map +1 -0
  53. package/dist/cli/search-graph-enrichment.d.ts +16 -0
  54. package/dist/cli/search-graph-enrichment.d.ts.map +1 -0
  55. package/dist/cli/search-graph-enrichment.js +428 -0
  56. package/dist/cli/search-graph-enrichment.js.map +1 -0
  57. package/dist/cli/system.d.ts +34 -0
  58. package/dist/cli/system.d.ts.map +1 -0
  59. package/dist/cli/system.js +89 -0
  60. package/dist/cli/system.js.map +1 -0
  61. package/dist/cli/vector-store-policy.d.ts +116 -0
  62. package/dist/cli/vector-store-policy.d.ts.map +1 -0
  63. package/dist/cli/vector-store-policy.js +160 -0
  64. package/dist/cli/vector-store-policy.js.map +1 -0
  65. package/dist/cli/version.d.ts +3 -0
  66. package/dist/cli/version.d.ts.map +1 -0
  67. package/dist/cli/version.js +3 -0
  68. package/dist/cli/version.js.map +1 -0
  69. package/dist/cli/workspace.d.ts +105 -0
  70. package/dist/cli/workspace.d.ts.map +1 -0
  71. package/dist/cli/workspace.js +215 -0
  72. package/dist/cli/workspace.js.map +1 -0
  73. package/dist/commands/complexity.d.ts +72 -0
  74. package/dist/commands/complexity.d.ts.map +1 -0
  75. package/dist/commands/complexity.js +580 -0
  76. package/dist/commands/complexity.js.map +1 -0
  77. package/dist/commands/doctor.d.ts +66 -0
  78. package/dist/commands/doctor.d.ts.map +1 -0
  79. package/dist/commands/doctor.js +764 -0
  80. package/dist/commands/doctor.js.map +1 -0
  81. package/dist/commands/doctor.languages.d.ts +37 -0
  82. package/dist/commands/doctor.languages.d.ts.map +1 -0
  83. package/dist/commands/doctor.languages.js +143 -0
  84. package/dist/commands/doctor.languages.js.map +1 -0
  85. package/dist/commands/doctor.storage.d.ts +17 -0
  86. package/dist/commands/doctor.storage.d.ts.map +1 -0
  87. package/dist/commands/doctor.storage.js +91 -0
  88. package/dist/commands/doctor.storage.js.map +1 -0
  89. package/dist/commands/extensions/add.d.ts +10 -0
  90. package/dist/commands/extensions/add.d.ts.map +1 -0
  91. package/dist/commands/extensions/add.js +213 -0
  92. package/dist/commands/extensions/add.js.map +1 -0
  93. package/dist/commands/extensions/configure.d.ts +5 -0
  94. package/dist/commands/extensions/configure.d.ts.map +1 -0
  95. package/dist/commands/extensions/configure.js +58 -0
  96. package/dist/commands/extensions/configure.js.map +1 -0
  97. package/dist/commands/extensions/container.d.ts +15 -0
  98. package/dist/commands/extensions/container.d.ts.map +1 -0
  99. package/dist/commands/extensions/container.js +135 -0
  100. package/dist/commands/extensions/container.js.map +1 -0
  101. package/dist/commands/extensions/context.d.ts +37 -0
  102. package/dist/commands/extensions/context.d.ts.map +1 -0
  103. package/dist/commands/extensions/context.js +72 -0
  104. package/dist/commands/extensions/context.js.map +1 -0
  105. package/dist/commands/extensions/enable.d.ts +6 -0
  106. package/dist/commands/extensions/enable.d.ts.map +1 -0
  107. package/dist/commands/extensions/enable.js +180 -0
  108. package/dist/commands/extensions/enable.js.map +1 -0
  109. package/dist/commands/extensions/environment.d.ts +74 -0
  110. package/dist/commands/extensions/environment.d.ts.map +1 -0
  111. package/dist/commands/extensions/environment.js +168 -0
  112. package/dist/commands/extensions/environment.js.map +1 -0
  113. package/dist/commands/extensions/feature-scan.d.ts +48 -0
  114. package/dist/commands/extensions/feature-scan.d.ts.map +1 -0
  115. package/dist/commands/extensions/feature-scan.js +156 -0
  116. package/dist/commands/extensions/feature-scan.js.map +1 -0
  117. package/dist/commands/extensions/invoke.d.ts +60 -0
  118. package/dist/commands/extensions/invoke.d.ts.map +1 -0
  119. package/dist/commands/extensions/invoke.js +275 -0
  120. package/dist/commands/extensions/invoke.js.map +1 -0
  121. package/dist/commands/extensions/list.d.ts +5 -0
  122. package/dist/commands/extensions/list.d.ts.map +1 -0
  123. package/dist/commands/extensions/list.js +125 -0
  124. package/dist/commands/extensions/list.js.map +1 -0
  125. package/dist/commands/extensions/logs.d.ts +5 -0
  126. package/dist/commands/extensions/logs.d.ts.map +1 -0
  127. package/dist/commands/extensions/logs.js +74 -0
  128. package/dist/commands/extensions/logs.js.map +1 -0
  129. package/dist/commands/extensions/provision.d.ts +36 -0
  130. package/dist/commands/extensions/provision.d.ts.map +1 -0
  131. package/dist/commands/extensions/provision.js +137 -0
  132. package/dist/commands/extensions/provision.js.map +1 -0
  133. package/dist/commands/extensions/remove.d.ts +5 -0
  134. package/dist/commands/extensions/remove.d.ts.map +1 -0
  135. package/dist/commands/extensions/remove.js +77 -0
  136. package/dist/commands/extensions/remove.js.map +1 -0
  137. package/dist/commands/extensions/render.d.ts +16 -0
  138. package/dist/commands/extensions/render.d.ts.map +1 -0
  139. package/dist/commands/extensions/render.js +25 -0
  140. package/dist/commands/extensions/render.js.map +1 -0
  141. package/dist/commands/extensions/run.d.ts +30 -0
  142. package/dist/commands/extensions/run.d.ts.map +1 -0
  143. package/dist/commands/extensions/run.js +292 -0
  144. package/dist/commands/extensions/run.js.map +1 -0
  145. package/dist/commands/extensions/secret-store.d.ts +15 -0
  146. package/dist/commands/extensions/secret-store.d.ts.map +1 -0
  147. package/dist/commands/extensions/secret-store.js +164 -0
  148. package/dist/commands/extensions/secret-store.js.map +1 -0
  149. package/dist/commands/extensions/setup.d.ts +17 -0
  150. package/dist/commands/extensions/setup.d.ts.map +1 -0
  151. package/dist/commands/extensions/setup.js +94 -0
  152. package/dist/commands/extensions/setup.js.map +1 -0
  153. package/dist/commands/extensions/source.d.ts +47 -0
  154. package/dist/commands/extensions/source.d.ts.map +1 -0
  155. package/dist/commands/extensions/source.js +142 -0
  156. package/dist/commands/extensions/source.js.map +1 -0
  157. package/dist/commands/extensions/state.d.ts +62 -0
  158. package/dist/commands/extensions/state.d.ts.map +1 -0
  159. package/dist/commands/extensions/state.js +177 -0
  160. package/dist/commands/extensions/state.js.map +1 -0
  161. package/dist/commands/extensions/status.d.ts +9 -0
  162. package/dist/commands/extensions/status.d.ts.map +1 -0
  163. package/dist/commands/extensions/status.js +239 -0
  164. package/dist/commands/extensions/status.js.map +1 -0
  165. package/dist/commands/extensions.d.ts +3 -0
  166. package/dist/commands/extensions.d.ts.map +1 -0
  167. package/dist/commands/extensions.js +223 -0
  168. package/dist/commands/extensions.js.map +1 -0
  169. package/dist/commands/flow/index.d.ts +3 -0
  170. package/dist/commands/flow/index.d.ts.map +1 -0
  171. package/dist/commands/flow/index.js +295 -0
  172. package/dist/commands/flow/index.js.map +1 -0
  173. package/dist/commands/flow/limits.d.ts +12 -0
  174. package/dist/commands/flow/limits.d.ts.map +1 -0
  175. package/dist/commands/flow/limits.js +13 -0
  176. package/dist/commands/flow/limits.js.map +1 -0
  177. package/dist/commands/flow/output.d.ts +8 -0
  178. package/dist/commands/flow/output.d.ts.map +1 -0
  179. package/dist/commands/flow/output.js +11 -0
  180. package/dist/commands/flow/output.js.map +1 -0
  181. package/dist/commands/flow/render.d.ts +51 -0
  182. package/dist/commands/flow/render.d.ts.map +1 -0
  183. package/dist/commands/flow/render.js +220 -0
  184. package/dist/commands/flow/render.js.map +1 -0
  185. package/dist/commands/flow/select.d.ts +31 -0
  186. package/dist/commands/flow/select.d.ts.map +1 -0
  187. package/dist/commands/flow/select.js +62 -0
  188. package/dist/commands/flow/select.js.map +1 -0
  189. package/dist/commands/graph/boundaries-input.d.ts +26 -0
  190. package/dist/commands/graph/boundaries-input.d.ts.map +1 -0
  191. package/dist/commands/graph/boundaries-input.js +54 -0
  192. package/dist/commands/graph/boundaries-input.js.map +1 -0
  193. package/dist/commands/graph/boundaries.d.ts +4 -0
  194. package/dist/commands/graph/boundaries.d.ts.map +1 -0
  195. package/dist/commands/graph/boundaries.js +141 -0
  196. package/dist/commands/graph/boundaries.js.map +1 -0
  197. package/dist/commands/graph/bounds.d.ts +16 -0
  198. package/dist/commands/graph/bounds.d.ts.map +1 -0
  199. package/dist/commands/graph/bounds.js +22 -0
  200. package/dist/commands/graph/bounds.js.map +1 -0
  201. package/dist/commands/graph/category-clusters.d.ts +20 -0
  202. package/dist/commands/graph/category-clusters.d.ts.map +1 -0
  203. package/dist/commands/graph/category-clusters.js +158 -0
  204. package/dist/commands/graph/category-clusters.js.map +1 -0
  205. package/dist/commands/graph/feature-3d.d.ts +22 -0
  206. package/dist/commands/graph/feature-3d.d.ts.map +1 -0
  207. package/dist/commands/graph/feature-3d.js +114 -0
  208. package/dist/commands/graph/feature-3d.js.map +1 -0
  209. package/dist/commands/graph/feature-clusters.d.ts +17 -0
  210. package/dist/commands/graph/feature-clusters.d.ts.map +1 -0
  211. package/dist/commands/graph/feature-clusters.js +94 -0
  212. package/dist/commands/graph/feature-clusters.js.map +1 -0
  213. package/dist/commands/graph/feature-html.d.ts +26 -0
  214. package/dist/commands/graph/feature-html.d.ts.map +1 -0
  215. package/dist/commands/graph/feature-html.js +314 -0
  216. package/dist/commands/graph/feature-html.js.map +1 -0
  217. package/dist/commands/graph/feature-map.d.ts +31 -0
  218. package/dist/commands/graph/feature-map.d.ts.map +1 -0
  219. package/dist/commands/graph/feature-map.js +217 -0
  220. package/dist/commands/graph/feature-map.js.map +1 -0
  221. package/dist/commands/graph/feature-model.d.ts +55 -0
  222. package/dist/commands/graph/feature-model.d.ts.map +1 -0
  223. package/dist/commands/graph/feature-model.js +167 -0
  224. package/dist/commands/graph/feature-model.js.map +1 -0
  225. package/dist/commands/graph/feature-untangle-motion.d.ts +33 -0
  226. package/dist/commands/graph/feature-untangle-motion.d.ts.map +1 -0
  227. package/dist/commands/graph/feature-untangle-motion.js +155 -0
  228. package/dist/commands/graph/feature-untangle-motion.js.map +1 -0
  229. package/dist/commands/graph/index.d.ts +3 -0
  230. package/dist/commands/graph/index.d.ts.map +1 -0
  231. package/dist/commands/graph/index.js +414 -0
  232. package/dist/commands/graph/index.js.map +1 -0
  233. package/dist/commands/graph/render.d.ts +63 -0
  234. package/dist/commands/graph/render.d.ts.map +1 -0
  235. package/dist/commands/graph/render.js +352 -0
  236. package/dist/commands/graph/render.js.map +1 -0
  237. package/dist/commands/graph/select.d.ts +34 -0
  238. package/dist/commands/graph/select.d.ts.map +1 -0
  239. package/dist/commands/graph/select.js +55 -0
  240. package/dist/commands/graph/select.js.map +1 -0
  241. package/dist/commands/index/index.d.ts +6 -0
  242. package/dist/commands/index/index.d.ts.map +1 -0
  243. package/dist/commands/index/index.js +461 -0
  244. package/dist/commands/index/index.js.map +1 -0
  245. package/dist/commands/index/render.d.ts +53 -0
  246. package/dist/commands/index/render.d.ts.map +1 -0
  247. package/dist/commands/index/render.js +205 -0
  248. package/dist/commands/index/render.js.map +1 -0
  249. package/dist/commands/index/target.d.ts +34 -0
  250. package/dist/commands/index/target.d.ts.map +1 -0
  251. package/dist/commands/index/target.js +97 -0
  252. package/dist/commands/index/target.js.map +1 -0
  253. package/dist/commands/index-watch.d.ts +30 -0
  254. package/dist/commands/index-watch.d.ts.map +1 -0
  255. package/dist/commands/index-watch.js +138 -0
  256. package/dist/commands/index-watch.js.map +1 -0
  257. package/dist/commands/init/command.d.ts +25 -0
  258. package/dist/commands/init/command.d.ts.map +1 -0
  259. package/dist/commands/init/command.js +198 -0
  260. package/dist/commands/init/command.js.map +1 -0
  261. package/dist/commands/init/config-draft.d.ts +48 -0
  262. package/dist/commands/init/config-draft.d.ts.map +1 -0
  263. package/dist/commands/init/config-draft.js +201 -0
  264. package/dist/commands/init/config-draft.js.map +1 -0
  265. package/dist/commands/init/diff.d.ts +33 -0
  266. package/dist/commands/init/diff.d.ts.map +1 -0
  267. package/dist/commands/init/diff.js +109 -0
  268. package/dist/commands/init/diff.js.map +1 -0
  269. package/dist/commands/init/http-probe.d.ts +26 -0
  270. package/dist/commands/init/http-probe.d.ts.map +1 -0
  271. package/dist/commands/init/http-probe.js +144 -0
  272. package/dist/commands/init/http-probe.js.map +1 -0
  273. package/dist/commands/init/ignore-rules.d.ts +70 -0
  274. package/dist/commands/init/ignore-rules.d.ts.map +1 -0
  275. package/dist/commands/init/ignore-rules.js +146 -0
  276. package/dist/commands/init/ignore-rules.js.map +1 -0
  277. package/dist/commands/init/index.d.ts +33 -0
  278. package/dist/commands/init/index.d.ts.map +1 -0
  279. package/dist/commands/init/index.js +32 -0
  280. package/dist/commands/init/index.js.map +1 -0
  281. package/dist/commands/init/integrations-apply.d.ts +50 -0
  282. package/dist/commands/init/integrations-apply.d.ts.map +1 -0
  283. package/dist/commands/init/integrations-apply.js +452 -0
  284. package/dist/commands/init/integrations-apply.js.map +1 -0
  285. package/dist/commands/init/integrations-plan.d.ts +68 -0
  286. package/dist/commands/init/integrations-plan.d.ts.map +1 -0
  287. package/dist/commands/init/integrations-plan.js +515 -0
  288. package/dist/commands/init/integrations-plan.js.map +1 -0
  289. package/dist/commands/init/integrations.d.ts +5 -0
  290. package/dist/commands/init/integrations.d.ts.map +1 -0
  291. package/dist/commands/init/integrations.js +4 -0
  292. package/dist/commands/init/integrations.js.map +1 -0
  293. package/dist/commands/init/languages.d.ts +55 -0
  294. package/dist/commands/init/languages.d.ts.map +1 -0
  295. package/dist/commands/init/languages.js +245 -0
  296. package/dist/commands/init/languages.js.map +1 -0
  297. package/dist/commands/init/product-context.d.ts +63 -0
  298. package/dist/commands/init/product-context.d.ts.map +1 -0
  299. package/dist/commands/init/product-context.js +390 -0
  300. package/dist/commands/init/product-context.js.map +1 -0
  301. package/dist/commands/init/render.d.ts +38 -0
  302. package/dist/commands/init/render.d.ts.map +1 -0
  303. package/dist/commands/init/render.js +501 -0
  304. package/dist/commands/init/render.js.map +1 -0
  305. package/dist/commands/init/report.d.ts +24 -0
  306. package/dist/commands/init/report.d.ts.map +1 -0
  307. package/dist/commands/init/report.js +163 -0
  308. package/dist/commands/init/report.js.map +1 -0
  309. package/dist/commands/init/run.d.ts +71 -0
  310. package/dist/commands/init/run.d.ts.map +1 -0
  311. package/dist/commands/init/run.js +253 -0
  312. package/dist/commands/init/run.js.map +1 -0
  313. package/dist/commands/init/services.d.ts +82 -0
  314. package/dist/commands/init/services.d.ts.map +1 -0
  315. package/dist/commands/init/services.js +209 -0
  316. package/dist/commands/init/services.js.map +1 -0
  317. package/dist/commands/init/storage.d.ts +8 -0
  318. package/dist/commands/init/storage.d.ts.map +1 -0
  319. package/dist/commands/init/storage.js +102 -0
  320. package/dist/commands/init/storage.js.map +1 -0
  321. package/dist/commands/init/toml.d.ts +65 -0
  322. package/dist/commands/init/toml.d.ts.map +1 -0
  323. package/dist/commands/init/toml.js +159 -0
  324. package/dist/commands/init/toml.js.map +1 -0
  325. package/dist/commands/init/topology.d.ts +54 -0
  326. package/dist/commands/init/topology.d.ts.map +1 -0
  327. package/dist/commands/init/topology.js +146 -0
  328. package/dist/commands/init/topology.js.map +1 -0
  329. package/dist/commands/init/types.d.ts +334 -0
  330. package/dist/commands/init/types.d.ts.map +1 -0
  331. package/dist/commands/init/types.js +31 -0
  332. package/dist/commands/init/types.js.map +1 -0
  333. package/dist/commands/init/wizard-terminal.d.ts +36 -0
  334. package/dist/commands/init/wizard-terminal.d.ts.map +1 -0
  335. package/dist/commands/init/wizard-terminal.js +163 -0
  336. package/dist/commands/init/wizard-terminal.js.map +1 -0
  337. package/dist/commands/init/wizard.d.ts +25 -0
  338. package/dist/commands/init/wizard.d.ts.map +1 -0
  339. package/dist/commands/init/wizard.js +358 -0
  340. package/dist/commands/init/wizard.js.map +1 -0
  341. package/dist/commands/mcp.d.ts +4 -0
  342. package/dist/commands/mcp.d.ts.map +1 -0
  343. package/dist/commands/mcp.js +111 -0
  344. package/dist/commands/mcp.js.map +1 -0
  345. package/dist/commands/product-test-runner.d.ts +4 -0
  346. package/dist/commands/product-test-runner.d.ts.map +1 -0
  347. package/dist/commands/product-test-runner.js +85 -0
  348. package/dist/commands/product-test-runner.js.map +1 -0
  349. package/dist/commands/product.d.ts +16 -0
  350. package/dist/commands/product.d.ts.map +1 -0
  351. package/dist/commands/product.js +262 -0
  352. package/dist/commands/product.js.map +1 -0
  353. package/dist/commands/query.d.ts +114 -0
  354. package/dist/commands/query.d.ts.map +1 -0
  355. package/dist/commands/query.js +783 -0
  356. package/dist/commands/query.js.map +1 -0
  357. package/dist/commands/scan.d.ts +10 -0
  358. package/dist/commands/scan.d.ts.map +1 -0
  359. package/dist/commands/scan.js +302 -0
  360. package/dist/commands/scan.js.map +1 -0
  361. package/dist/commands/sdd.d.ts +24 -0
  362. package/dist/commands/sdd.d.ts.map +1 -0
  363. package/dist/commands/sdd.js +195 -0
  364. package/dist/commands/sdd.js.map +1 -0
  365. package/dist/commands/unavailable.d.ts +40 -0
  366. package/dist/commands/unavailable.d.ts.map +1 -0
  367. package/dist/commands/unavailable.js +73 -0
  368. package/dist/commands/unavailable.js.map +1 -0
  369. package/dist/commands/watch/analyze.d.ts +69 -0
  370. package/dist/commands/watch/analyze.d.ts.map +1 -0
  371. package/dist/commands/watch/analyze.js +402 -0
  372. package/dist/commands/watch/analyze.js.map +1 -0
  373. package/dist/commands/watch/cli.d.ts +8 -0
  374. package/dist/commands/watch/cli.d.ts.map +1 -0
  375. package/dist/commands/watch/cli.js +97 -0
  376. package/dist/commands/watch/cli.js.map +1 -0
  377. package/dist/commands/watch/delta.d.ts +46 -0
  378. package/dist/commands/watch/delta.d.ts.map +1 -0
  379. package/dist/commands/watch/delta.js +170 -0
  380. package/dist/commands/watch/delta.js.map +1 -0
  381. package/dist/commands/watch/events.d.ts +214 -0
  382. package/dist/commands/watch/events.d.ts.map +1 -0
  383. package/dist/commands/watch/events.js +13 -0
  384. package/dist/commands/watch/events.js.map +1 -0
  385. package/dist/commands/watch/index.d.ts +19 -0
  386. package/dist/commands/watch/index.d.ts.map +1 -0
  387. package/dist/commands/watch/index.js +15 -0
  388. package/dist/commands/watch/index.js.map +1 -0
  389. package/dist/commands/watch/options.d.ts +43 -0
  390. package/dist/commands/watch/options.d.ts.map +1 -0
  391. package/dist/commands/watch/options.js +193 -0
  392. package/dist/commands/watch/options.js.map +1 -0
  393. package/dist/commands/watch/render.d.ts +26 -0
  394. package/dist/commands/watch/render.d.ts.map +1 -0
  395. package/dist/commands/watch/render.js +175 -0
  396. package/dist/commands/watch/render.js.map +1 -0
  397. package/dist/commands/watch/run.d.ts +14 -0
  398. package/dist/commands/watch/run.d.ts.map +1 -0
  399. package/dist/commands/watch/run.js +460 -0
  400. package/dist/commands/watch/run.js.map +1 -0
  401. package/dist/commands/watch/runtime.d.ts +67 -0
  402. package/dist/commands/watch/runtime.d.ts.map +1 -0
  403. package/dist/commands/watch/runtime.js +149 -0
  404. package/dist/commands/watch/runtime.js.map +1 -0
  405. package/dist/commands/watch-command.d.ts +3 -0
  406. package/dist/commands/watch-command.d.ts.map +1 -0
  407. package/dist/commands/watch-command.js +273 -0
  408. package/dist/commands/watch-command.js.map +1 -0
  409. package/dist/entry-point.d.ts +11 -0
  410. package/dist/entry-point.d.ts.map +1 -0
  411. package/dist/entry-point.js +65 -0
  412. package/dist/entry-point.js.map +1 -0
  413. package/dist/index.d.ts +38 -0
  414. package/dist/index.d.ts.map +1 -0
  415. package/dist/index.js +245 -0
  416. package/dist/index.js.map +1 -0
  417. package/dist/mcp/boundaries-schema.d.ts +262 -0
  418. package/dist/mcp/boundaries-schema.d.ts.map +1 -0
  419. package/dist/mcp/boundaries-schema.js +183 -0
  420. package/dist/mcp/boundaries-schema.js.map +1 -0
  421. package/dist/mcp/default-runtime.d.ts +16 -0
  422. package/dist/mcp/default-runtime.d.ts.map +1 -0
  423. package/dist/mcp/default-runtime.js +718 -0
  424. package/dist/mcp/default-runtime.js.map +1 -0
  425. package/dist/mcp/envelope.d.ts +13 -0
  426. package/dist/mcp/envelope.d.ts.map +1 -0
  427. package/dist/mcp/envelope.js +29 -0
  428. package/dist/mcp/envelope.js.map +1 -0
  429. package/dist/mcp/index.d.ts +8 -0
  430. package/dist/mcp/index.d.ts.map +1 -0
  431. package/dist/mcp/index.js +8 -0
  432. package/dist/mcp/index.js.map +1 -0
  433. package/dist/mcp/output-schemas.d.ts +5928 -0
  434. package/dist/mcp/output-schemas.d.ts.map +1 -0
  435. package/dist/mcp/output-schemas.js +2814 -0
  436. package/dist/mcp/output-schemas.js.map +1 -0
  437. package/dist/mcp/path-sandbox.d.ts +35 -0
  438. package/dist/mcp/path-sandbox.d.ts.map +1 -0
  439. package/dist/mcp/path-sandbox.js +128 -0
  440. package/dist/mcp/path-sandbox.js.map +1 -0
  441. package/dist/mcp/server.d.ts +155 -0
  442. package/dist/mcp/server.d.ts.map +1 -0
  443. package/dist/mcp/server.js +257 -0
  444. package/dist/mcp/server.js.map +1 -0
  445. package/dist/mcp/stdio.d.ts +20 -0
  446. package/dist/mcp/stdio.d.ts.map +1 -0
  447. package/dist/mcp/stdio.js +71 -0
  448. package/dist/mcp/stdio.js.map +1 -0
  449. package/dist/mcp/tools.d.ts +355 -0
  450. package/dist/mcp/tools.d.ts.map +1 -0
  451. package/dist/mcp/tools.js +319 -0
  452. package/dist/mcp/tools.js.map +1 -0
  453. package/dist/mcp/types.d.ts +15 -0
  454. package/dist/mcp/types.d.ts.map +1 -0
  455. package/dist/mcp/types.js +45 -0
  456. package/dist/mcp/types.js.map +1 -0
  457. package/package.json +99 -3
  458. package/src/cli/args.ts +231 -0
  459. package/src/cli/command.ts +146 -0
  460. package/src/cli/deadline.ts +56 -0
  461. package/src/cli/embedder-deadline.ts +187 -0
  462. package/src/cli/exit.ts +94 -0
  463. package/src/cli/graphs.ts +191 -0
  464. package/src/cli/index-freshness.ts +303 -0
  465. package/src/cli/index-refresh.ts +125 -0
  466. package/src/cli/index-state.ts +1217 -0
  467. package/src/cli/io.ts +56 -0
  468. package/src/cli/language-support.ts +203 -0
  469. package/src/cli/renewing-lease.ts +121 -0
  470. package/src/cli/search-graph-enrichment.ts +639 -0
  471. package/src/cli/system.ts +94 -0
  472. package/src/cli/vector-store-policy.ts +213 -0
  473. package/src/cli/version.ts +2 -0
  474. package/src/cli/workspace.ts +324 -0
  475. package/src/commands/complexity.ts +776 -0
  476. package/src/commands/doctor.languages.ts +187 -0
  477. package/src/commands/doctor.storage.ts +124 -0
  478. package/src/commands/doctor.ts +946 -0
  479. package/src/commands/extensions/add.ts +312 -0
  480. package/src/commands/extensions/configure.ts +82 -0
  481. package/src/commands/extensions/container.ts +209 -0
  482. package/src/commands/extensions/context.ts +109 -0
  483. package/src/commands/extensions/enable.ts +237 -0
  484. package/src/commands/extensions/environment.ts +218 -0
  485. package/src/commands/extensions/feature-scan.ts +232 -0
  486. package/src/commands/extensions/invoke.ts +368 -0
  487. package/src/commands/extensions/list.ts +158 -0
  488. package/src/commands/extensions/logs.ts +104 -0
  489. package/src/commands/extensions/provision.ts +206 -0
  490. package/src/commands/extensions/remove.ts +110 -0
  491. package/src/commands/extensions/render.ts +32 -0
  492. package/src/commands/extensions/run.ts +386 -0
  493. package/src/commands/extensions/secret-store.ts +223 -0
  494. package/src/commands/extensions/setup.ts +140 -0
  495. package/src/commands/extensions/source.ts +189 -0
  496. package/src/commands/extensions/state.ts +252 -0
  497. package/src/commands/extensions/status.ts +320 -0
  498. package/src/commands/extensions.ts +280 -0
  499. package/src/commands/flow/index.ts +402 -0
  500. package/src/commands/flow/limits.ts +14 -0
  501. package/src/commands/flow/output.ts +16 -0
  502. package/src/commands/flow/render.ts +318 -0
  503. package/src/commands/flow/select.ts +101 -0
  504. package/src/commands/graph/boundaries-input.ts +63 -0
  505. package/src/commands/graph/boundaries.ts +182 -0
  506. package/src/commands/graph/bounds.ts +25 -0
  507. package/src/commands/graph/category-clusters.ts +194 -0
  508. package/src/commands/graph/feature-3d.ts +141 -0
  509. package/src/commands/graph/feature-clusters.ts +125 -0
  510. package/src/commands/graph/feature-html.ts +336 -0
  511. package/src/commands/graph/feature-map.ts +270 -0
  512. package/src/commands/graph/feature-model.ts +234 -0
  513. package/src/commands/graph/feature-untangle-motion.ts +192 -0
  514. package/src/commands/graph/index.ts +562 -0
  515. package/src/commands/graph/render.ts +503 -0
  516. package/src/commands/graph/select.ts +77 -0
  517. package/src/commands/index/index.ts +595 -0
  518. package/src/commands/index/render.ts +325 -0
  519. package/src/commands/index/target.ts +136 -0
  520. package/src/commands/index-watch.ts +206 -0
  521. package/src/commands/init/command.ts +238 -0
  522. package/src/commands/init/config-draft.ts +235 -0
  523. package/src/commands/init/diff.ts +117 -0
  524. package/src/commands/init/http-probe.ts +150 -0
  525. package/src/commands/init/ignore-rules.ts +170 -0
  526. package/src/commands/init/index.ts +63 -0
  527. package/src/commands/init/integrations-apply.ts +618 -0
  528. package/src/commands/init/integrations-plan.ts +634 -0
  529. package/src/commands/init/integrations.ts +8 -0
  530. package/src/commands/init/languages.ts +320 -0
  531. package/src/commands/init/product-context.ts +576 -0
  532. package/src/commands/init/render.ts +598 -0
  533. package/src/commands/init/report.ts +204 -0
  534. package/src/commands/init/run.ts +349 -0
  535. package/src/commands/init/services.ts +271 -0
  536. package/src/commands/init/storage.ts +136 -0
  537. package/src/commands/init/toml.ts +174 -0
  538. package/src/commands/init/topology.ts +192 -0
  539. package/src/commands/init/types.ts +366 -0
  540. package/src/commands/init/wizard-terminal.ts +206 -0
  541. package/src/commands/init/wizard.ts +450 -0
  542. package/src/commands/mcp.ts +123 -0
  543. package/src/commands/product-test-runner.ts +80 -0
  544. package/src/commands/product.ts +331 -0
  545. package/src/commands/query.ts +1032 -0
  546. package/src/commands/scan.ts +360 -0
  547. package/src/commands/sdd.ts +243 -0
  548. package/src/commands/unavailable.ts +92 -0
  549. package/src/commands/watch/README.md +160 -0
  550. package/src/commands/watch/analyze.ts +600 -0
  551. package/src/commands/watch/cli.ts +108 -0
  552. package/src/commands/watch/delta.ts +186 -0
  553. package/src/commands/watch/events.ts +235 -0
  554. package/src/commands/watch/index.ts +53 -0
  555. package/src/commands/watch/options.ts +234 -0
  556. package/src/commands/watch/render.ts +240 -0
  557. package/src/commands/watch/run.ts +553 -0
  558. package/src/commands/watch/runtime.ts +167 -0
  559. package/src/commands/watch-command.ts +294 -0
  560. package/src/entry-point.ts +67 -0
  561. package/src/index.ts +291 -0
  562. package/src/mcp/boundaries-schema.ts +193 -0
  563. package/src/mcp/default-runtime.ts +1034 -0
  564. package/src/mcp/envelope.ts +57 -0
  565. package/src/mcp/index.ts +28 -0
  566. package/src/mcp/output-schemas.ts +3071 -0
  567. package/src/mcp/path-sandbox.ts +156 -0
  568. package/src/mcp/server.ts +358 -0
  569. package/src/mcp/stdio.ts +92 -0
  570. package/src/mcp/tools.ts +563 -0
  571. package/src/mcp/types.ts +66 -0
@@ -0,0 +1,109 @@
1
+ /**
2
+ * The shared read path of the extension commands.
3
+ *
4
+ * Every command starts from the same picture: which manifests were found in
5
+ * the user roots, which were rejected and why, which were deliberately
6
+ * ignored and why, which acknowledgments exist, and what the CLI recorded
7
+ * about earlier runs. Building that once keeps `list`, `run` and `enable`
8
+ * from drifting apart in what they consider "installed".
9
+ */
10
+ import {
11
+ discoverExtensions,
12
+ evaluateLicenseGate,
13
+ loadLicenseAcknowledgments,
14
+ type ExtensionDiscoveryResultV1,
15
+ type LicenseAcknowledgmentV1,
16
+ type LicenseGateDecisionV1,
17
+ type LoadedExtensionV1,
18
+ } from "@untangle-code/extension-runtime";
19
+
20
+ import type { ExtensionEnvironmentV1 } from "./environment.js";
21
+ import { loadCliState, type CliStateV1 } from "./state.js";
22
+
23
+ export interface ExtensionContextV1 {
24
+ discovery: ExtensionDiscoveryResultV1;
25
+ acknowledgments: LicenseAcknowledgmentV1[];
26
+ state: CliStateV1;
27
+ /** Everything that was skipped, unreadable or ignored, with its reason (E4). */
28
+ warnings: string[];
29
+ }
30
+
31
+ /** Reads discovery, acknowledgments and CLI state in one go. */
32
+ export async function loadExtensionContext(
33
+ environment: ExtensionEnvironmentV1,
34
+ ): Promise<ExtensionContextV1> {
35
+ const discovery = await discoverExtensions(environment.fs, {
36
+ roots: environment.roots,
37
+ projectRoots: environment.projectRoots,
38
+ });
39
+ const acknowledgments = await loadLicenseAcknowledgments(environment.fs, {
40
+ userDataDirectory: environment.userDataDir,
41
+ projectRoots: environment.projectRoots,
42
+ });
43
+ const state = await loadCliState(environment.fs, environment.userDataDir);
44
+ return {
45
+ discovery,
46
+ acknowledgments: acknowledgments.acknowledgments,
47
+ state: state.state,
48
+ warnings: [...acknowledgments.warnings, ...state.warnings],
49
+ };
50
+ }
51
+
52
+ /** Finds a loaded extension by id, or null. */
53
+ export function findExtension(
54
+ context: ExtensionContextV1,
55
+ extensionId: string,
56
+ ): LoadedExtensionV1 | null {
57
+ return context.discovery.extensions.find((entry) => entry.manifest.id === extensionId) ?? null;
58
+ }
59
+
60
+ /**
61
+ * Evaluates both gates for one extension against the stored acknowledgments.
62
+ *
63
+ * `ruleset` is the effective ruleset of the intended run; without one the
64
+ * manifest's `defaultRuleset` applies, which is what the runtime would use.
65
+ */
66
+ export function gateFor(
67
+ context: ExtensionContextV1,
68
+ extension: LoadedExtensionV1,
69
+ ruleset?: string,
70
+ ): LicenseGateDecisionV1 {
71
+ const effective = ruleset ?? extension.manifest.defaultRuleset;
72
+ return evaluateLicenseGate({
73
+ extension,
74
+ acknowledgments: context.acknowledgments,
75
+ ...(effective === undefined ? {} : { ruleset: effective }),
76
+ });
77
+ }
78
+
79
+ /**
80
+ * Explains why an id is not installed, naming the manifests that were
81
+ * rejected or ignored for it. "Not found" without a reason is exactly the
82
+ * silent skip E4 forbids.
83
+ */
84
+ export function explainMissing(context: ExtensionContextV1, extensionId: string): string {
85
+ const rejected = context.discovery.rejected.filter(
86
+ (entry) =>
87
+ entry.directoryName === extensionId || entry.manifestPath.includes(`/${extensionId}/`),
88
+ );
89
+ if (rejected.length > 0) {
90
+ const reasons = rejected
91
+ .flatMap((entry) => entry.issues.map((issue) => `${issue.field}: ${issue.message}`))
92
+ .join("; ");
93
+ return `extension "${extensionId}" has a manifest but it was rejected — ${reasons}`;
94
+ }
95
+ const ignored = context.discovery.ignored.filter((entry) =>
96
+ entry.manifestPath.includes(`/${extensionId}/`),
97
+ );
98
+ if (ignored.length > 0) {
99
+ const reasons = ignored.map((entry) => `${entry.reason}: ${entry.detail}`).join("; ");
100
+ return `extension "${extensionId}" was found but not loaded — ${reasons}`;
101
+ }
102
+ const roots = context.discovery.rootsScanned
103
+ .map((entry) => `${entry.root}${entry.exists ? "" : " (does not exist)"}`)
104
+ .join(", ");
105
+ return (
106
+ `no extension "${extensionId}" is installed; searched: ${roots}. ` +
107
+ `Install one with: untangle extensions add --from <path-or-url>`
108
+ );
109
+ }
@@ -0,0 +1,237 @@
1
+ /**
2
+ * `untangle extensions enable <id>` / `disable <id>`
3
+ *
4
+ * These exist because the runtime's license gate prints them. When a gate is
5
+ * unacknowledged the runtime hands back the exact command that would grant
6
+ * the acknowledgment (extensions.md §9.5), and a printed command that does
7
+ * not exist is worse than no hint at all.
8
+ *
9
+ * `enable` records the opt-in and, with the acknowledgment flags, the
10
+ * personal license declaration. It starts nothing: no process, no pull, no
11
+ * container (X1). `disable` reverses the opt-in and, with `--revoke-license`,
12
+ * the declaration (§9.3).
13
+ *
14
+ * The tool gate and the ruleset gate are separate. `--acknowledge-license`
15
+ * covers the tool ONLY; a restricted ruleset still needs its own
16
+ * `--acknowledge-ruleset=<id>`, which is repeatable.
17
+ */
18
+ import {
19
+ buildAcknowledgment,
20
+ createNodeProcessRunner,
21
+ defaultProcessLimits,
22
+ } from "@untangle-code/extension-runtime";
23
+
24
+ import { boolFlag, listFlag, type ParsedArgs } from "../../cli/args.js";
25
+ import { EXIT, OperationalError, UsageError } from "../../cli/exit.js";
26
+ import { line, note, type Io } from "../../cli/io.js";
27
+
28
+ import { createContainerCli } from "./container.js";
29
+ import { explainMissing, findExtension, gateFor, loadExtensionContext } from "./context.js";
30
+ import type { ExtensionEnvironmentV1 } from "./environment.js";
31
+ import { composeFilePath } from "./provision.js";
32
+ import { emitJson } from "./render.js";
33
+ import {
34
+ revokeAcknowledgments,
35
+ saveAcknowledgments,
36
+ saveCliState,
37
+ upsertAcknowledgment,
38
+ } from "./state.js";
39
+
40
+ export async function runEnable(
41
+ environment: ExtensionEnvironmentV1,
42
+ args: ParsedArgs,
43
+ io: Io,
44
+ format: "text" | "json",
45
+ ): Promise<number> {
46
+ const extensionId = args.positionals[1];
47
+ if (extensionId === undefined) {
48
+ throw new UsageError(
49
+ "`untangle extensions enable` needs an extension id.",
50
+ "Run `untangle extensions list` to see the installed ids.",
51
+ );
52
+ }
53
+ const context = await loadExtensionContext(environment);
54
+ const extension = findExtension(context, extensionId);
55
+ if (extension === null) {
56
+ throw new OperationalError(
57
+ explainMissing(context, extensionId),
58
+ "Install it first: untangle extensions add --from=<path-or-url>",
59
+ );
60
+ }
61
+
62
+ let acknowledgments = context.acknowledgments;
63
+ const acknowledgedNow: string[] = [];
64
+ if (boolFlag(args, "acknowledge-license")) {
65
+ acknowledgments = upsertAcknowledgment(
66
+ acknowledgments,
67
+ buildAcknowledgment({
68
+ manifest: extension.manifest,
69
+ acknowledgedAt: environment.clock.nowIso(),
70
+ acknowledgedBy: environment.userName,
71
+ }),
72
+ );
73
+ acknowledgedNow.push(`tool:${extensionId}`);
74
+ }
75
+ for (const ruleset of listFlag(args, "acknowledge-ruleset")) {
76
+ acknowledgments = upsertAcknowledgment(
77
+ acknowledgments,
78
+ buildAcknowledgment({
79
+ manifest: extension.manifest,
80
+ ruleset,
81
+ acknowledgedAt: environment.clock.nowIso(),
82
+ acknowledgedBy: environment.userName,
83
+ }),
84
+ );
85
+ acknowledgedNow.push(`ruleset:${ruleset}`);
86
+ }
87
+ let acknowledgmentFile: string | undefined;
88
+ if (acknowledgedNow.length > 0) {
89
+ acknowledgmentFile = await saveAcknowledgments(
90
+ environment.fs,
91
+ environment.userDataDir,
92
+ acknowledgments,
93
+ );
94
+ }
95
+
96
+ const enabled = context.state.enabled.includes(extensionId)
97
+ ? context.state.enabled
98
+ : [...context.state.enabled, extensionId];
99
+ const statePath = await saveCliState(environment.fs, environment.userDataDir, {
100
+ ...context.state,
101
+ enabled,
102
+ });
103
+
104
+ const gate = gateFor({ ...context, acknowledgments }, extension);
105
+
106
+ if (format === "json") {
107
+ emitJson(io, {
108
+ command: "extensions enable",
109
+ extensionId,
110
+ enabled: true,
111
+ started: false,
112
+ stateFile: statePath,
113
+ acknowledgedNow,
114
+ acknowledgmentFile,
115
+ licenseGate: {
116
+ allowed: gate.allowed,
117
+ tool: { status: gate.tool.status, reason: gate.tool.reason },
118
+ rulesets: gate.rulesets.map((entry) => ({
119
+ ruleset: entry.ruleset,
120
+ status: entry.status,
121
+ reason: entry.reason,
122
+ })),
123
+ acknowledgeCommands: gate.acknowledgeCommands,
124
+ },
125
+ });
126
+ } else {
127
+ line(io, `enabled "${extensionId}" — nothing was started (X1).`);
128
+ line(io, ` state ${statePath}`);
129
+ line(io, ` license ${gate.tool.status} — ${gate.tool.reason}`);
130
+ for (const entry of gate.rulesets) {
131
+ line(io, ` ruleset ${entry.ruleset}: ${entry.status} — ${entry.reason}`);
132
+ }
133
+ }
134
+
135
+ if (!gate.allowed) {
136
+ note(io, "The license gate is still open; run:");
137
+ for (const command of gate.acknowledgeCommands) {
138
+ note(io, ` ${command}`);
139
+ }
140
+ return EXIT.environment;
141
+ }
142
+ return EXIT.ok;
143
+ }
144
+
145
+ export async function runDisable(
146
+ environment: ExtensionEnvironmentV1,
147
+ args: ParsedArgs,
148
+ io: Io,
149
+ format: "text" | "json",
150
+ ): Promise<number> {
151
+ const extensionId = args.positionals[1];
152
+ if (extensionId === undefined) {
153
+ throw new UsageError(
154
+ "`untangle extensions disable` needs an extension id.",
155
+ "Run `untangle extensions list` to see the installed ids.",
156
+ );
157
+ }
158
+ // Die Flag-Pruefung steht VOR jeder Zustandsaenderung. Zuvor lag sie danach:
159
+ // ein Aufruf, den die CLI im selben Atemzug als Aufruffehler zurueckwies,
160
+ // hatte die Extension bereits deaktiviert. Ein abgelehnter Befehl darf nichts
161
+ // getan haben.
162
+ const removeContainer = boolFlag(args, "remove-container");
163
+ const removeVolumes = boolFlag(args, "remove-volumes");
164
+ if (removeVolumes && !removeContainer) {
165
+ throw new UsageError(
166
+ "--remove-volumes only applies together with --remove-container.",
167
+ `Run untangle extensions disable ${extensionId} --remove-container --remove-volumes`,
168
+ );
169
+ }
170
+
171
+ const context = await loadExtensionContext(environment);
172
+ const statePath = await saveCliState(environment.fs, environment.userDataDir, {
173
+ ...context.state,
174
+ enabled: context.state.enabled.filter((id) => id !== extensionId),
175
+ });
176
+ // `--remove-container` fasst NUR den eigenen Container an; die Besitzprobe
177
+ // liegt im Adapter und laesst einen fremden gleichen Namens unberuehrt.
178
+ // Volumes bleiben ohne die zweite, ausdrueckliche Anweisung erhalten: ein
179
+ // geloeschtes Volume ist die einzige hier moegliche Handlung, die Arbeit
180
+ // vernichtet, die niemand wiederherstellen kann.
181
+ let containerDetail: string | undefined;
182
+ if (removeContainer) {
183
+ const installed = findExtension(context, extensionId);
184
+ const manifest = installed?.manifest;
185
+ if (manifest?.container === undefined) {
186
+ containerDetail = `"${extensionId}" declares no container; nothing to remove`;
187
+ } else {
188
+ const containerCli = createContainerCli({
189
+ processRunner: createNodeProcessRunner(environment.clock),
190
+ limits: { ...defaultProcessLimits(), timeoutMs: 120_000 },
191
+ ...(environment.env["UNTANGLE_CONTAINER_CLI"] === undefined
192
+ ? {}
193
+ : { command: environment.env["UNTANGLE_CONTAINER_CLI"] }),
194
+ });
195
+ const down = await containerCli.down({
196
+ manifest,
197
+ composeFilePath: composeFilePath(environment.userDataDir, manifest.id),
198
+ removeVolumes,
199
+ });
200
+ containerDetail = down.detail;
201
+ }
202
+ }
203
+
204
+ let acknowledgmentFile: string | undefined;
205
+ const revoked = boolFlag(args, "revoke-license");
206
+ if (revoked) {
207
+ acknowledgmentFile = await saveAcknowledgments(
208
+ environment.fs,
209
+ environment.userDataDir,
210
+ revokeAcknowledgments(context.acknowledgments, extensionId, environment.clock.nowIso()),
211
+ );
212
+ }
213
+
214
+ if (format === "json") {
215
+ emitJson(io, {
216
+ command: "extensions disable",
217
+ extensionId,
218
+ enabled: false,
219
+ stateFile: statePath,
220
+ licenseAcknowledgment: revoked ? "revoked" : "kept",
221
+ acknowledgmentFile,
222
+ ...(containerDetail === undefined ? {} : { container: containerDetail }),
223
+ });
224
+ } else {
225
+ line(io, `disabled "${extensionId}".`);
226
+ line(
227
+ io,
228
+ revoked
229
+ ? ` license acknowledgment revoked in ${String(acknowledgmentFile)}`
230
+ : " license acknowledgment kept (use --revoke-license to drop it)",
231
+ );
232
+ if (containerDetail !== undefined) {
233
+ line(io, ` container ${containerDetail}`);
234
+ }
235
+ }
236
+ return EXIT.ok;
237
+ }
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Ports and locations the extension commands run against.
3
+ *
4
+ * Everything the commands touch arrives here as data or as a port: the file
5
+ * system, the clock, randomness, the search roots, the user data directory
6
+ * and — the load-bearing one — the PROJECT roots.
7
+ *
8
+ * ## Why project roots exist at all
9
+ *
10
+ * A manifest describes how to start a program. If Untangle read manifests
11
+ * from the working directory, `git clone` of a stranger's repository would be
12
+ * enough to put a tool definition in front of the runtime, and one
13
+ * `untangle extensions run` away from executing it. So project directories
14
+ * are a boundary, not a search path: `discoverExtensions` never scans them,
15
+ * and `loadExtensionFrom` refuses a path inside one unless the user types
16
+ * `--allow-project-local` in that very invocation.
17
+ *
18
+ * The same reasoning puts license acknowledgments in the user data directory
19
+ * (extensions.md §9.2): a `.untangle/` file can be committed, and a committed
20
+ * acknowledgment would inherit one person's declaration to a whole team.
21
+ */
22
+ import { homedir, userInfo } from "node:os";
23
+ import { basename, dirname, isAbsolute, join, resolve } from "node:path";
24
+
25
+ import type { Clock, FileSystemPort, Random } from "@untangle-code/domain";
26
+ import {
27
+ isInsideDirectory,
28
+ resolveExtensionRoots,
29
+ userDataDirectory,
30
+ type ExtensionPathEnvironmentV1,
31
+ } from "@untangle-code/extension-runtime";
32
+ import { NodeFileSystem } from "@untangle-code/scanner/node-fs";
33
+
34
+ import { systemClock, systemRandom } from "../../cli/system.js";
35
+
36
+ export interface ExtensionEnvironmentV1 {
37
+ fs: FileSystemPort;
38
+ clock: Clock;
39
+ random: Random;
40
+ /** Directory the user invoked the CLI from, canonicalized where possible. */
41
+ cwd: string;
42
+ /** Search roots for user-installed extensions; `roots[0]` is the install target. */
43
+ roots: string[];
44
+ /** OS-specific user data directory (holds the acknowledgment file). */
45
+ userDataDir: string;
46
+ /** Directories that MUST NOT be scanned for manifests. */
47
+ projectRoots: string[];
48
+ /** OS user name — an acknowledgment is a personal declaration. */
49
+ userName: string;
50
+ env: Readonly<Record<string, string | undefined>>;
51
+ }
52
+
53
+ export interface CreateExtensionEnvironmentOptions {
54
+ cwd: string;
55
+ env: Readonly<Record<string, string | undefined>>;
56
+ fs?: FileSystemPort;
57
+ clock?: Clock;
58
+ random?: Random;
59
+ homeDir?: string;
60
+ platform?: string;
61
+ userName?: string;
62
+ }
63
+
64
+ export async function createExtensionEnvironment(
65
+ options: CreateExtensionEnvironmentOptions,
66
+ ): Promise<ExtensionEnvironmentV1> {
67
+ const fs = options.fs ?? new NodeFileSystem();
68
+ const cwd = await canonicalize(fs, resolve(options.cwd));
69
+ const platform = options.platform ?? process.platform;
70
+ const pathEnvironment: ExtensionPathEnvironmentV1 = {
71
+ homeDir: options.homeDir ?? homeDirFrom(options.env, platform),
72
+ platform,
73
+ env: options.env,
74
+ };
75
+ return {
76
+ fs,
77
+ clock: options.clock ?? systemClock,
78
+ random: options.random ?? systemRandom,
79
+ cwd,
80
+ roots: await Promise.all(
81
+ resolveExtensionRoots(pathEnvironment).map((root) => canonicalize(fs, root)),
82
+ ),
83
+ userDataDir: userDataDirectory(pathEnvironment),
84
+ projectRoots: await discoverProjectRoots(fs, cwd, pathEnvironment.homeDir),
85
+ userName: options.userName ?? safeUserName(),
86
+ env: options.env,
87
+ };
88
+ }
89
+
90
+ /**
91
+ * Marker files that identify a directory as somebody's PROJECT rather than
92
+ * part of the user profile. `.git` is the decisive one — the threat this
93
+ * boundary exists for is a cloned repository — and the two Untangle markers
94
+ * cover a project that was shipped as an archive rather than a clone.
95
+ */
96
+ const PROJECT_MARKERS = [".git", ".untangle.json", ".untangle"] as const;
97
+
98
+ /**
99
+ * Determines which directories must be treated as project directories.
100
+ *
101
+ * Walks from `start` up to the filesystem root and collects every directory
102
+ * carrying a project marker; if at least one is found, `start` itself joins
103
+ * the list, because the working directory inside a project is part of that
104
+ * project.
105
+ *
106
+ * Two deliberate exclusions:
107
+ *
108
+ * - **The home directory is never a project root.** A dotfiles repository in
109
+ * `$HOME` is ordinary, and treating `$HOME` as a project would put
110
+ * `~/.untangle/extensions` inside a project directory — which would make the
111
+ * user's own extension root unscannable the moment they ran the CLI from
112
+ * their home directory. The boundary is meant to keep a stranger's
113
+ * repository out, not to lock people out of their own profile.
114
+ * - **A directory with no marker anywhere above it yields no project roots at
115
+ * all.** Without a marker there is no project to protect, and a bare
116
+ * directory the user made themselves is theirs. The consequence is stated
117
+ * openly: `add --from ./manifest.toml` in such a directory is NOT refused.
118
+ * A cloned repository always carries `.git`, so the case the boundary exists
119
+ * for is still covered.
120
+ */
121
+ export async function discoverProjectRoots(
122
+ fs: FileSystemPort,
123
+ start: string,
124
+ homeDir?: string,
125
+ ): Promise<string[]> {
126
+ const home = homeDir === undefined ? undefined : resolve(homeDir);
127
+ const found: string[] = [];
128
+ let current = start;
129
+ for (;;) {
130
+ if (current !== home && (await hasProjectMarker(fs, current))) {
131
+ found.push(current);
132
+ }
133
+ const parent = dirname(current);
134
+ if (parent === current) {
135
+ break;
136
+ }
137
+ current = parent;
138
+ }
139
+ if (found.length === 0) {
140
+ return [];
141
+ }
142
+ return found.includes(start) ? found : [start, ...found];
143
+ }
144
+
145
+ async function hasProjectMarker(fs: FileSystemPort, directory: string): Promise<boolean> {
146
+ for (const marker of PROJECT_MARKERS) {
147
+ if ((await fs.stat(join(directory, marker))) !== null) {
148
+ return true;
149
+ }
150
+ }
151
+ return false;
152
+ }
153
+
154
+ /** True when `candidate` lies inside any of `roots`. */
155
+ export function isInsideAnyRoot(candidate: string, roots: readonly string[]): boolean {
156
+ return roots.some((root) => isInsideDirectory(candidate, root));
157
+ }
158
+
159
+ /** Resolves a user-supplied path against the working directory. */
160
+ export function resolveUserPath(cwd: string, path: string): string {
161
+ return isAbsolute(path) ? path : resolve(cwd, path);
162
+ }
163
+
164
+ /**
165
+ * Canonical form of a path, with symlinks resolved.
166
+ *
167
+ * This is not cosmetic. `isProjectLocalManifest` and `isInsideDirectory`
168
+ * compare LEXICALLY and say so: they never resolve symlinks, and the caller is
169
+ * expected to hand them canonical paths. Skipping this step would leave the
170
+ * project boundary trivially escapable — a symlink, or on macOS merely the
171
+ * `/var` → `/private/var` alias, is enough to make a path inside a project
172
+ * compare as if it were outside one.
173
+ *
174
+ * A path that does not exist yet still gets canonicalized as far as it does
175
+ * exist: the deepest existing ancestor is resolved and the remaining segments
176
+ * are re-appended. Failing the whole command over a not-yet-created file would
177
+ * be worse than a partially canonical answer, and the ancestor is the part
178
+ * that decides containment.
179
+ */
180
+ export async function canonicalize(fs: FileSystemPort, path: string): Promise<string> {
181
+ const tail: string[] = [];
182
+ let current = resolve(path);
183
+ for (;;) {
184
+ try {
185
+ const real = await fs.realPath(current);
186
+ return tail.length === 0 ? real : join(real, ...tail.reverse());
187
+ } catch {
188
+ const parent = dirname(current);
189
+ if (parent === current) {
190
+ return resolve(path);
191
+ }
192
+ tail.push(basename(current));
193
+ current = parent;
194
+ }
195
+ }
196
+ }
197
+
198
+ /**
199
+ * The home directory as the COMMAND CONTEXT sees it.
200
+ *
201
+ * `os.homedir()` reads the process environment, not the environment handed to
202
+ * this command. Preferring the context keeps the extension root, the
203
+ * acknowledgment file and the state file inside whatever profile the caller
204
+ * declared — which is what makes these commands testable without writing into
205
+ * the real user profile.
206
+ */
207
+ function homeDirFrom(env: Readonly<Record<string, string | undefined>>, platform: string): string {
208
+ const fromEnv = platform === "win32" ? env["USERPROFILE"] : env["HOME"];
209
+ return fromEnv !== undefined && fromEnv.trim() !== "" ? fromEnv : homedir();
210
+ }
211
+
212
+ function safeUserName(): string {
213
+ try {
214
+ return userInfo().username;
215
+ } catch {
216
+ return "unknown";
217
+ }
218
+ }