@untangle-code/cli 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (571) hide show
  1. package/LICENSE +661 -0
  2. package/NOTICE +90 -0
  3. package/README.md +451 -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,386 @@
1
+ /**
2
+ * `untangle extensions run <id>`
3
+ *
4
+ * Runs one installed extension and normalizes whatever it prints into
5
+ * `ExternalFindingV1` (X3). The order of the checks is the load-bearing part:
6
+ *
7
+ * license gate → availability probe → run → parse → normalize
8
+ *
9
+ * The gate comes first because a version probe is already a process start,
10
+ * and X5 forbids starting or pulling anything for a tool whose terms have not
11
+ * been acknowledged. Checking availability first and the license second would
12
+ * produce the same refusal — after having run the tool once.
13
+ *
14
+ * What comes out is evidence, never an Untangle metric: findings do not
15
+ * change the exit code, and no number here is ever folded into a complexity
16
+ * or risk value (X3). Everything the run could not resolve — a file outside
17
+ * the workspace, a position that does not exist, a severity that hit the
18
+ * mapping fallback — is reported with its reason rather than dropped (E4).
19
+ */
20
+ import { readFileSync } from "node:fs";
21
+ import { relative, resolve } from "node:path";
22
+
23
+ import type { ExternalFindingV1, SkipLedgerEntryV1 } from "@untangle-code/domain";
24
+ import { compareCodepoints } from "@untangle-code/domain";
25
+ import {
26
+ createLineOffsetResolver,
27
+ defaultProcessLimits,
28
+ normalizeToolPath,
29
+ type ExtensionHealthV1,
30
+ type ExtensionRunResultV1,
31
+ type FileResolutionV1,
32
+ type ProcessLimitsV1,
33
+ } from "@untangle-code/extension-runtime";
34
+
35
+ import { boolFlag, integerFlag, stringFlag, type ParsedArgs } from "../../cli/args.js";
36
+ import { EXIT, EnvironmentError, OperationalError, UsageError } from "../../cli/exit.js";
37
+ import { line, note, type Io } from "../../cli/io.js";
38
+
39
+ import { explainMissing, findExtension, gateFor, loadExtensionContext } from "./context.js";
40
+ import { resolveUserPath, type ExtensionEnvironmentV1 } from "./environment.js";
41
+ import { invokeExtension } from "./invoke.js";
42
+ import { emitJson, renderTable } from "./render.js";
43
+ import { saveCliState, summarizeRun } from "./state.js";
44
+
45
+ export interface RunDeps {
46
+ /** Injected in tests so no unit test opens a socket. */
47
+ fetchImpl?: typeof fetch;
48
+ signal?: AbortSignal;
49
+ }
50
+
51
+ export async function runRun(
52
+ environment: ExtensionEnvironmentV1,
53
+ args: ParsedArgs,
54
+ io: Io,
55
+ format: "text" | "json",
56
+ deps: RunDeps = {},
57
+ ): Promise<number> {
58
+ const command = args.positionals[0] === "setup" ? "extensions setup" : "extensions run";
59
+ const extensionId = args.positionals[1];
60
+ if (extensionId === undefined) {
61
+ throw new UsageError(
62
+ `\`untangle ${command}\` needs an extension id.`,
63
+ "Run `untangle extensions list` to see the installed ids.",
64
+ );
65
+ }
66
+
67
+ const context = await loadExtensionContext(environment);
68
+ const extension = findExtension(context, extensionId);
69
+ if (extension === null) {
70
+ throw new OperationalError(
71
+ explainMissing(context, extensionId),
72
+ "Install it first: untangle extensions add --from=<path-or-url>",
73
+ );
74
+ }
75
+ const manifest = extension.manifest;
76
+
77
+ const workspacePath = resolveUserPath(environment.cwd, stringFlag(args, "workspace") ?? ".");
78
+ const target = resolveUserPath(environment.cwd, stringFlag(args, "target") ?? workspacePath);
79
+ const ruleset = stringFlag(args, "ruleset") ?? manifest.defaultRuleset;
80
+
81
+ // --- license gate BEFORE any process start (X5) -------------------------
82
+ const gate = gateFor(context, extension, ruleset);
83
+ if (!gate.allowed) {
84
+ note(io, `EXTENSION_LICENSE_UNACKNOWLEDGED: ${extensionId} did not start.`);
85
+ note(io, ` ${gate.tool.reason}`);
86
+ for (const entry of gate.rulesets) {
87
+ if (entry.status !== "acknowledged" && entry.status !== "not_required") {
88
+ note(io, ` ruleset ${entry.ruleset}: ${entry.reason}`);
89
+ }
90
+ }
91
+ throw new EnvironmentError(
92
+ `The license gate for "${extensionId}" is not satisfied; nothing was started and nothing was pulled.`,
93
+ gate.acknowledgeCommands.join(" && "),
94
+ );
95
+ }
96
+
97
+ // Der eigentliche Lauf liegt in `invoke.ts` — als Daten hinein, als Ergebnis
98
+ // heraus. `runRun` ist die MENSCHLICHE Fassung davon: es uebersetzt einen
99
+ // nicht stattgefundenen Lauf in die Ausnahme, die ein einzelner Aufruf
100
+ // erwartet, und berichtet danach. Ein Sammelbericht ruft dieselbe Funktion
101
+ // auf und uebersetzt eben NICHT in eine Ausnahme.
102
+ const limits = readLimits(args);
103
+ const httpUrl = stringFlag(args, "url") ?? manifest.http?.defaultUrl;
104
+ const outcome = await invokeExtension({
105
+ environment,
106
+ context,
107
+ extension,
108
+ workspacePath,
109
+ target,
110
+ limits,
111
+ provisionConsent: boolFlag(args, "yes"),
112
+ ...(ruleset === undefined ? {} : { ruleset }),
113
+ ...(httpUrl === undefined ? {} : { httpUrl }),
114
+ ...(deps.fetchImpl === undefined ? {} : { fetchImpl: deps.fetchImpl }),
115
+ ...(deps.signal === undefined ? {} : { signal: deps.signal }),
116
+ onProvisionStep: (step) => {
117
+ note(io, ` ${step}`);
118
+ },
119
+ onProvisionPlanned: (detail) => {
120
+ note(io, ` ${detail}`);
121
+ },
122
+ resolveFile: workspaceFileResolver(workspacePath),
123
+ resolvePosition: createLineOffsetResolver(lazyWorkspaceContents(workspacePath)),
124
+ });
125
+
126
+ if (outcome.status === "not_run") {
127
+ note(io, `${extensionId} did not run: ${outcome.detail}`);
128
+ if (outcome.reason === "license_gate_open") {
129
+ throw new EnvironmentError(
130
+ `The license gate for "${extensionId}" is not satisfied; nothing was started and nothing was pulled.`,
131
+ outcome.nextStep ?? "acknowledge the licence first",
132
+ );
133
+ }
134
+ throw new EnvironmentError(
135
+ `"${extensionId}" did not run (${outcome.reason}).`,
136
+ outcome.nextStep ?? "see the reason above",
137
+ );
138
+ }
139
+
140
+ const { health, result } = outcome;
141
+
142
+ await saveCliState(environment.fs, environment.userDataDir, {
143
+ ...context.state,
144
+ lastRuns: {
145
+ ...context.state.lastRuns,
146
+ [extensionId]: summarizeRun(result.run),
147
+ },
148
+ });
149
+
150
+ report(io, format, {
151
+ command,
152
+ extensionId,
153
+ workspacePath,
154
+ target,
155
+ health,
156
+ result,
157
+ warnings: context.warnings,
158
+ });
159
+
160
+ if (result.run.exitStatus === "completed") {
161
+ return EXIT.ok;
162
+ }
163
+ throw new OperationalError(
164
+ `"${extensionId}" ended with status ${result.run.exitStatus}` +
165
+ `${result.run.errorCode === undefined ? "" : ` (${result.run.errorCode})`}.`,
166
+ describeNextStep(health, result),
167
+ );
168
+ }
169
+
170
+ function readLimits(args: ParsedArgs): ProcessLimitsV1 {
171
+ const limits = defaultProcessLimits();
172
+ const timeout = integerFlag(args, "timeout", limits.timeoutMs);
173
+ const maxOutput = integerFlag(args, "max-output-bytes", limits.maxOutputBytes);
174
+ if (timeout <= 0) {
175
+ throw new UsageError(
176
+ "--timeout expects a positive number of milliseconds.",
177
+ "Example: --timeout=60000",
178
+ );
179
+ }
180
+ if (maxOutput <= 0) {
181
+ throw new UsageError(
182
+ "--max-output-bytes expects a positive byte count.",
183
+ "Example: --max-output-bytes=1048576",
184
+ );
185
+ }
186
+ return { ...limits, timeoutMs: timeout, maxOutputBytes: maxOutput };
187
+ }
188
+
189
+ /**
190
+ * Maps a tool-reported path onto workspace-relative form.
191
+ *
192
+ * `fileId` is deliberately absent with a stated reason: this command runs
193
+ * against the working tree, not an index generation, so there is no file
194
+ * identity to attach. Inventing one would make a finding look joined to an
195
+ * index that never saw it.
196
+ */
197
+ export function workspaceFileResolver(
198
+ workspacePath: string,
199
+ ): (toolPath: string) => FileResolutionV1 {
200
+ return (toolPath: string): FileResolutionV1 => {
201
+ const normalized = normalizeToolPath(toolPath);
202
+ if (normalized === "") {
203
+ return { fileIdMissingReason: "the tool reported an empty path" };
204
+ }
205
+ const absolute = /^([a-zA-Z]:\/|\/)/.test(normalized)
206
+ ? normalized
207
+ : resolve(workspacePath, normalized);
208
+ const relativePath = relative(workspacePath, absolute).split("\\").join("/");
209
+ if (relativePath === "" || relativePath.startsWith("../")) {
210
+ return {
211
+ fileIdMissingReason:
212
+ `the tool reported "${toolPath}", which is outside the analyzed workspace ` +
213
+ `"${workspacePath}"`,
214
+ };
215
+ }
216
+ return {
217
+ relativePath,
218
+ fileIdMissingReason:
219
+ "no index generation is loaded; this run resolves paths against the working tree only",
220
+ };
221
+ };
222
+ }
223
+
224
+ /**
225
+ * A `ReadonlyMap` view over the working tree that reads a file the first time
226
+ * a position inside it must be resolved.
227
+ *
228
+ * Reading the whole workspace eagerly to translate a handful of line numbers
229
+ * would be the wrong trade. A failed read is cached as "absent", which makes
230
+ * the position unresolvable — and therefore a ledger entry rather than a
231
+ * guess (E4).
232
+ */
233
+ export function lazyWorkspaceContents(workspacePath: string): ReadonlyMap<string, string> {
234
+ const cache = new Map<string, string | null>();
235
+ const load = (relativePath: string): string | null => {
236
+ if (cache.has(relativePath)) {
237
+ return cache.get(relativePath) ?? null;
238
+ }
239
+ let content: string | null;
240
+ try {
241
+ content = readFileSync(resolve(workspacePath, relativePath), "utf8");
242
+ } catch {
243
+ content = null;
244
+ }
245
+ cache.set(relativePath, content);
246
+ return content;
247
+ };
248
+ return Object.assign(new Map<string, string>(), {
249
+ get(key: string): string | undefined {
250
+ return load(key) ?? undefined;
251
+ },
252
+ has(key: string): boolean {
253
+ return load(key) !== null;
254
+ },
255
+ });
256
+ }
257
+
258
+ interface ReportInput {
259
+ command: "extensions setup" | "extensions run";
260
+ extensionId: string;
261
+ workspacePath: string;
262
+ target: string;
263
+ health: ExtensionHealthV1;
264
+ result: ExtensionRunResultV1;
265
+ warnings: readonly string[];
266
+ }
267
+
268
+ function report(io: Io, format: "text" | "json", input: ReportInput): void {
269
+ const { result } = input;
270
+ if (format === "json") {
271
+ emitJson(io, {
272
+ command: input.command,
273
+ extensionId: input.extensionId,
274
+ workspace: input.workspacePath,
275
+ target: input.target,
276
+ evidenceOnly: true,
277
+ health: input.health,
278
+ run: result.run,
279
+ findings: result.findings,
280
+ measurements: result.measurements,
281
+ skipped: result.skipped,
282
+ error: result.error === undefined ? undefined : { message: result.error.message },
283
+ warnings: input.warnings,
284
+ });
285
+ } else {
286
+ line(io, `run ${result.run.runId} — ${input.extensionId} (${result.run.exitStatus})`);
287
+ line(io, ` invocation ${result.run.invocation ?? "(none)"}`);
288
+ line(io, ` tool ${result.run.toolVersion}`);
289
+ line(io, ` format ${result.run.outputFormat} via ${result.run.formatParserVersion}`);
290
+ line(io, ` target ${input.target}`);
291
+ line(io, ` wall time ${String(result.run.resources.wallTimeMs)} ms`);
292
+ line(
293
+ io,
294
+ ` findings ${String(result.run.findingsTotal)} (${describeCounts(result.run.findingCounts)})`,
295
+ );
296
+
297
+ if (result.findings.length > 0) {
298
+ line(io, "");
299
+ const rows = [...result.findings]
300
+ .sort(
301
+ (left, right) =>
302
+ compareCodepoints(left.filePath, right.filePath) ||
303
+ left.sourceRange.startByte - right.sourceRange.startByte ||
304
+ compareCodepoints(left.ruleId, right.ruleId),
305
+ )
306
+ .map((finding) => [
307
+ finding.severity.normalized,
308
+ `${finding.filePath}:${String(finding.sourceRange.startLine ?? 0)}`,
309
+ finding.ruleId,
310
+ firstLine(finding.message),
311
+ ]);
312
+ for (const rendered of renderTable(["SEVERITY", "LOCATION", "RULE", "MESSAGE"], rows)) {
313
+ line(io, rendered);
314
+ }
315
+ line(io, "");
316
+ line(
317
+ io,
318
+ "These are external findings — evidence from a third-party tool. They are never folded " +
319
+ "into Untangle complexity or risk numbers (X3).",
320
+ );
321
+ }
322
+ }
323
+
324
+ reportUnmappedSeverities(io, result.findings);
325
+ for (const entry of result.skipped) {
326
+ note(io, `skipped ${describeSkip(entry)}`);
327
+ }
328
+ for (const warning of result.run.warnings) {
329
+ note(io, `warning: ${warning}`);
330
+ }
331
+ for (const warning of input.warnings) {
332
+ note(io, `warning: ${warning}`);
333
+ }
334
+ for (const error of result.run.errors) {
335
+ note(io, `${error.code}: ${error.message}`);
336
+ }
337
+ if (result.run.exitStatus !== "completed") {
338
+ for (const reason of input.health.unavailableReasons) {
339
+ note(io, ` ${reason.invocation}: ${reason.detail}`);
340
+ }
341
+ }
342
+ }
343
+
344
+ function describeNextStep(health: ExtensionHealthV1, result: ExtensionRunResultV1): string {
345
+ if (!health.available) {
346
+ const first = health.unavailableReasons[0];
347
+ return first === undefined
348
+ ? "Check the manifest's invocation section against what is installed on this machine."
349
+ : `Make the ${first.invocation} invocation work: ${first.detail}`;
350
+ }
351
+ return result.error === undefined
352
+ ? "Re-run with --format=json to see the full run record."
353
+ : result.error.message;
354
+ }
355
+
356
+ function reportUnmappedSeverities(io: Io, findings: readonly ExternalFindingV1[]): void {
357
+ const unmapped = findings.filter((finding) => !finding.severity.mappingMatched);
358
+ if (unmapped.length === 0) {
359
+ return;
360
+ }
361
+ const originals = [...new Set(unmapped.map((finding) => finding.severity.original))].sort(
362
+ compareCodepoints,
363
+ );
364
+ note(
365
+ io,
366
+ `warning: ${String(unmapped.length)} finding(s) hit the severity fallback; the manifest maps ` +
367
+ `no rule for: ${originals.join(", ")}`,
368
+ );
369
+ }
370
+
371
+ function describeCounts(counts: Readonly<Record<string, number>>): string {
372
+ const parts = Object.entries(counts)
373
+ .filter(([, value]) => value > 0)
374
+ .map(([key, value]) => `${key} ${String(value)}`);
375
+ return parts.length === 0 ? "none" : parts.join(", ");
376
+ }
377
+
378
+ function describeSkip(entry: SkipLedgerEntryV1): string {
379
+ const where = entry.path === undefined ? entry.subjectKind : `${entry.subjectKind} ${entry.path}`;
380
+ return `${where}: ${entry.reason} — ${entry.detail}`;
381
+ }
382
+
383
+ function firstLine(message: string): string {
384
+ const text = message.split("\n")[0] ?? "";
385
+ return text.length > 96 ? `${text.slice(0, 93)}...` : text;
386
+ }
@@ -0,0 +1,223 @@
1
+ /** Private, endpoint-bound extension credentials; never part of project configuration. */
2
+ import { randomUUID } from "node:crypto";
3
+ import { constants } from "node:fs";
4
+ import { lstat, mkdir, open, rename, rm } from "node:fs/promises";
5
+ import { dirname, join } from "node:path";
6
+
7
+ import type { ExtensionManifestV1 } from "@untangle-code/domain";
8
+
9
+ import { canonicalize, isInsideAnyRoot, type ExtensionEnvironmentV1 } from "./environment.js";
10
+
11
+ export function secretStorePath(environment: ExtensionEnvironmentV1, id: string): string {
12
+ return join(environment.userDataDir, "extension-secrets", `${id}.json`);
13
+ }
14
+
15
+ export function credentialEndpoint(url?: string): string | null {
16
+ if (url === undefined) return null;
17
+ const parsed = new URL(url);
18
+ if (
19
+ !["http:", "https:"].includes(parsed.protocol) ||
20
+ parsed.username ||
21
+ parsed.password ||
22
+ parsed.search ||
23
+ parsed.hash
24
+ ) {
25
+ throw new Error(
26
+ "Credential endpoint must be an HTTP(S) base URL without credentials, query or fragment.",
27
+ );
28
+ }
29
+ return parsed.href.replace(/\/$/u, "");
30
+ }
31
+
32
+ function isRecord(value: unknown): value is Record<string, unknown> {
33
+ return value !== null && typeof value === "object" && !Array.isArray(value);
34
+ }
35
+
36
+ /** Error messages intentionally contain neither raw JSON nor credential values. */
37
+ export function parseSecretValues(
38
+ value: unknown,
39
+ manifest: ExtensionManifestV1,
40
+ ): Record<string, string> {
41
+ if (!isRecord(value))
42
+ throw new Error("Credential configuration must be an object keyed by declared secret names.");
43
+ const declared = new Set(manifest.secrets.map((secret) => secret.name));
44
+ const entries = Object.entries(value);
45
+ if (
46
+ entries.some(
47
+ ([name, secret]) =>
48
+ !declared.has(name) || typeof secret !== "string" || secret.includes("\0"),
49
+ )
50
+ ) {
51
+ throw new Error(
52
+ "Credential configuration contains an undeclared secret or a non-string value.",
53
+ );
54
+ }
55
+ return Object.fromEntries(entries) as Record<string, string>;
56
+ }
57
+
58
+ async function checkDirectory(
59
+ environment: ExtensionEnvironmentV1,
60
+ create: boolean,
61
+ ): Promise<string> {
62
+ const directory = dirname(secretStorePath(environment, "placeholder"));
63
+ const canonical = await canonicalize(environment.fs, directory);
64
+ if (isInsideAnyRoot(canonical, environment.projectRoots)) {
65
+ throw new Error("Extension credentials must be stored outside project directories.");
66
+ }
67
+ if (create) await mkdir(directory, { recursive: true, mode: 0o700 });
68
+ try {
69
+ const info = await lstat(directory);
70
+ if (
71
+ !info.isDirectory() ||
72
+ info.isSymbolicLink() ||
73
+ (process.platform !== "win32" &&
74
+ ((info.mode & 0o077) !== 0 || info.uid !== process.getuid?.()))
75
+ ) {
76
+ throw new Error(
77
+ `Credential directory must be owned by this user with mode 0700: ${directory}`,
78
+ );
79
+ }
80
+ } catch (error) {
81
+ if (hasCode(error, "ENOENT") && !create) return directory;
82
+ throw error;
83
+ }
84
+ return directory;
85
+ }
86
+
87
+ export function hasCode(error: unknown, code: string): boolean {
88
+ return isRecord(error) && error["code"] === code;
89
+ }
90
+
91
+ export async function readStoredSecrets(
92
+ environment: ExtensionEnvironmentV1,
93
+ manifest: ExtensionManifestV1,
94
+ url = manifest.http?.defaultUrl,
95
+ ): Promise<Record<string, string>> {
96
+ if (manifest.secrets.length === 0) return {};
97
+ await checkDirectory(environment, false);
98
+ const path = secretStorePath(environment, manifest.id);
99
+ let handle;
100
+ try {
101
+ handle = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
102
+ } catch (error) {
103
+ if (hasCode(error, "ENOENT")) return {};
104
+ throw new Error(`Cannot safely open credential configuration: ${path}`);
105
+ }
106
+ try {
107
+ const info = await handle.stat();
108
+ if (
109
+ !info.isFile() ||
110
+ info.size > 1_048_576 ||
111
+ (process.platform !== "win32" &&
112
+ ((info.mode & 0o077) !== 0 || info.uid !== process.getuid?.()))
113
+ ) {
114
+ throw new Error(`Credential configuration must be a user-owned file with mode 0600: ${path}`);
115
+ }
116
+ let value: unknown;
117
+ try {
118
+ value = JSON.parse(await handle.readFile("utf8"));
119
+ } catch {
120
+ throw new Error(`Invalid JSON in credential configuration: ${path}`);
121
+ }
122
+ if (!isRecord(value) || value["schemaVersion"] !== 1 || value["extensionId"] !== manifest.id) {
123
+ throw new Error(`Invalid credential configuration schema: ${path}`);
124
+ }
125
+ if (value["endpoint"] !== credentialEndpoint(url)) {
126
+ throw new Error(
127
+ "Stored credentials belong to a different endpoint; configure credentials for the selected endpoint first.",
128
+ );
129
+ }
130
+ return parseSecretValues(value["secrets"], manifest);
131
+ } finally {
132
+ await handle.close();
133
+ }
134
+ }
135
+
136
+ export function secretEnvironment(
137
+ environment: ExtensionEnvironmentV1,
138
+ manifest: ExtensionManifestV1,
139
+ stored: Readonly<Record<string, string>>,
140
+ ): Record<string, string | undefined> {
141
+ const env = { ...environment.env };
142
+ for (const secret of manifest.secrets) {
143
+ if (!env[secret.envVar] && stored[secret.name]) env[secret.envVar] = stored[secret.name];
144
+ }
145
+ return env;
146
+ }
147
+
148
+ /** A complete environment override does not depend on an old endpoint's config. */
149
+ export async function resolveSecretEnvironment(
150
+ environment: ExtensionEnvironmentV1,
151
+ manifest: ExtensionManifestV1,
152
+ url = manifest.http?.defaultUrl,
153
+ ): Promise<Record<string, string | undefined>> {
154
+ const needsStoredValues = manifest.secrets.some(
155
+ (secret) => !secret.setupOnly && !environment.env[secret.envVar],
156
+ );
157
+ return secretEnvironment(
158
+ environment,
159
+ manifest,
160
+ needsStoredValues ? await readStoredSecrets(environment, manifest, url) : {},
161
+ );
162
+ }
163
+
164
+ /** Caller holds the per-extension lock while changing stored credentials. */
165
+ export async function writeStoredSecrets(
166
+ environment: ExtensionEnvironmentV1,
167
+ manifest: ExtensionManifestV1,
168
+ values: Readonly<Record<string, string>>,
169
+ url = manifest.http?.defaultUrl,
170
+ ): Promise<void> {
171
+ await checkDirectory(environment, true);
172
+ const secrets = parseSecretValues(values, manifest);
173
+ const path = secretStorePath(environment, manifest.id);
174
+ const temporary = `${path}.${randomUUID()}.tmp`;
175
+ try {
176
+ const handle = await open(temporary, "wx", 0o600);
177
+ try {
178
+ await handle.writeFile(
179
+ JSON.stringify(
180
+ {
181
+ schemaVersion: 1,
182
+ extensionId: manifest.id,
183
+ endpoint: credentialEndpoint(url),
184
+ secrets,
185
+ },
186
+ null,
187
+ 2,
188
+ ) + "\n",
189
+ );
190
+ await handle.sync();
191
+ } finally {
192
+ await handle.close();
193
+ }
194
+ await rename(temporary, path);
195
+ } finally {
196
+ await rm(temporary, { force: true });
197
+ }
198
+ }
199
+
200
+ export async function withSecretLock<T>(
201
+ environment: ExtensionEnvironmentV1,
202
+ id: string,
203
+ action: () => Promise<T>,
204
+ ): Promise<T> {
205
+ const directory = await checkDirectory(environment, true);
206
+ const path = join(directory, `${id}.lock`);
207
+ let handle;
208
+ try {
209
+ handle = await open(path, "wx", 0o600);
210
+ } catch (error) {
211
+ if (hasCode(error, "EEXIST"))
212
+ throw new Error(
213
+ `Credential setup is already locked for ${id}; retry after it finishes. If interrupted, inspect and remove ${path}.`,
214
+ );
215
+ throw new Error("Cannot lock the private credential store.");
216
+ }
217
+ try {
218
+ return await action();
219
+ } finally {
220
+ await handle.close();
221
+ await rm(path, { force: true });
222
+ }
223
+ }