pycforge-sdk 0.6.3__py3-none-any.whl

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 (559) hide show
  1. pycforge_sdk/__init__.py +6 -0
  2. pycforge_sdk/__main__.py +3 -0
  3. pycforge_sdk/catalogue.py +287 -0
  4. pycforge_sdk/cli.py +114 -0
  5. pycforge_sdk/connection.py +136 -0
  6. pycforge_sdk/discovery.py +227 -0
  7. pycforge_sdk/editing.py +84 -0
  8. pycforge_sdk/engine_launch.py +45 -0
  9. pycforge_sdk/engine_worker.py +53 -0
  10. pycforge_sdk/gui/__init__.py +1 -0
  11. pycforge_sdk/gui/__main__.py +3 -0
  12. pycforge_sdk/gui/app.py +36 -0
  13. pycforge_sdk/gui/dialogs.py +310 -0
  14. pycforge_sdk/gui/editor.py +412 -0
  15. pycforge_sdk/gui/help/index.html +9 -0
  16. pycforge_sdk/gui/identity.py +139 -0
  17. pycforge_sdk/gui/jobs.py +146 -0
  18. pycforge_sdk/gui/reference.py +39 -0
  19. pycforge_sdk/gui/resources/sdk-mark.png +0 -0
  20. pycforge_sdk/gui/scanner.py +134 -0
  21. pycforge_sdk/gui/startup.py +118 -0
  22. pycforge_sdk/gui/visual/__init__.py +1 -0
  23. pycforge_sdk/gui/visual/action_contract.py +550 -0
  24. pycforge_sdk/gui/visual/icons.py +117 -0
  25. pycforge_sdk/gui/visual/qt_actions.py +501 -0
  26. pycforge_sdk/gui/visual/qt_branding.py +47 -0
  27. pycforge_sdk/gui/visual/qt_dialog_chrome.py +337 -0
  28. pycforge_sdk/gui/visual/qt_file_icons.py +130 -0
  29. pycforge_sdk/gui/visual/qt_icons.py +80 -0
  30. pycforge_sdk/gui/visual/qt_screen_geometry.py +166 -0
  31. pycforge_sdk/gui/visual/qt_title_controls.py +333 -0
  32. pycforge_sdk/gui/visual/qt_window_chrome.py +314 -0
  33. pycforge_sdk/gui/visual/qt_window_resize.py +93 -0
  34. pycforge_sdk/gui/visual/qt_workspace_widgets.py +448 -0
  35. pycforge_sdk/gui/visual/resources/icons/128/add-document.png +0 -0
  36. pycforge_sdk/gui/visual/resources/icons/128/brand-mark.png +0 -0
  37. pycforge_sdk/gui/visual/resources/icons/128/bundle-search.png +0 -0
  38. pycforge_sdk/gui/visual/resources/icons/128/cancel.png +0 -0
  39. pycforge_sdk/gui/visual/resources/icons/128/check.png +0 -0
  40. pycforge_sdk/gui/visual/resources/icons/128/chevron-right.png +0 -0
  41. pycforge_sdk/gui/visual/resources/icons/128/close.png +0 -0
  42. pycforge_sdk/gui/visual/resources/icons/128/collapse-all.png +0 -0
  43. pycforge_sdk/gui/visual/resources/icons/128/command-palette.png +0 -0
  44. pycforge_sdk/gui/visual/resources/icons/128/convert.png +0 -0
  45. pycforge_sdk/gui/visual/resources/icons/128/copy.png +0 -0
  46. pycforge_sdk/gui/visual/resources/icons/128/cut.png +0 -0
  47. pycforge_sdk/gui/visual/resources/icons/128/decision-trace.png +0 -0
  48. pycforge_sdk/gui/visual/resources/icons/128/details.png +0 -0
  49. pycforge_sdk/gui/visual/resources/icons/128/diagnostics.png +0 -0
  50. pycforge_sdk/gui/visual/resources/icons/128/duplicate-line.png +0 -0
  51. pycforge_sdk/gui/visual/resources/icons/128/exit.png +0 -0
  52. pycforge_sdk/gui/visual/resources/icons/128/expand-all.png +0 -0
  53. pycforge_sdk/gui/visual/resources/icons/128/export.png +0 -0
  54. pycforge_sdk/gui/visual/resources/icons/128/find.png +0 -0
  55. pycforge_sdk/gui/visual/resources/icons/128/go-to-line.png +0 -0
  56. pycforge_sdk/gui/visual/resources/icons/128/go-to-output.png +0 -0
  57. pycforge_sdk/gui/visual/resources/icons/128/go-to-source.png +0 -0
  58. pycforge_sdk/gui/visual/resources/icons/128/help.png +0 -0
  59. pycforge_sdk/gui/visual/resources/icons/128/history.png +0 -0
  60. pycforge_sdk/gui/visual/resources/icons/128/indent.png +0 -0
  61. pycforge_sdk/gui/visual/resources/icons/128/link-c.png +0 -0
  62. pycforge_sdk/gui/visual/resources/icons/128/mappings.png +0 -0
  63. pycforge_sdk/gui/visual/resources/icons/128/module.png +0 -0
  64. pycforge_sdk/gui/visual/resources/icons/128/move-down.png +0 -0
  65. pycforge_sdk/gui/visual/resources/icons/128/move-line-down.png +0 -0
  66. pycforge_sdk/gui/visual/resources/icons/128/move-line-up.png +0 -0
  67. pycforge_sdk/gui/visual/resources/icons/128/move-up.png +0 -0
  68. pycforge_sdk/gui/visual/resources/icons/128/next.png +0 -0
  69. pycforge_sdk/gui/visual/resources/icons/128/open.png +0 -0
  70. pycforge_sdk/gui/visual/resources/icons/128/outdent.png +0 -0
  71. pycforge_sdk/gui/visual/resources/icons/128/outline.png +0 -0
  72. pycforge_sdk/gui/visual/resources/icons/128/paste.png +0 -0
  73. pycforge_sdk/gui/visual/resources/icons/128/previous.png +0 -0
  74. pycforge_sdk/gui/visual/resources/icons/128/primary-module.png +0 -0
  75. pycforge_sdk/gui/visual/resources/icons/128/redo.png +0 -0
  76. pycforge_sdk/gui/visual/resources/icons/128/remove-document.png +0 -0
  77. pycforge_sdk/gui/visual/resources/icons/128/replace.png +0 -0
  78. pycforge_sdk/gui/visual/resources/icons/128/save-as.png +0 -0
  79. pycforge_sdk/gui/visual/resources/icons/128/save.png +0 -0
  80. pycforge_sdk/gui/visual/resources/icons/128/select-all.png +0 -0
  81. pycforge_sdk/gui/visual/resources/icons/128/settings.png +0 -0
  82. pycforge_sdk/gui/visual/resources/icons/128/show-c.png +0 -0
  83. pycforge_sdk/gui/visual/resources/icons/128/split-view.png +0 -0
  84. pycforge_sdk/gui/visual/resources/icons/128/summary.png +0 -0
  85. pycforge_sdk/gui/visual/resources/icons/128/telemetry.png +0 -0
  86. pycforge_sdk/gui/visual/resources/icons/128/toggle-comment.png +0 -0
  87. pycforge_sdk/gui/visual/resources/icons/128/toggle-fold.png +0 -0
  88. pycforge_sdk/gui/visual/resources/icons/128/tools.png +0 -0
  89. pycforge_sdk/gui/visual/resources/icons/128/undo.png +0 -0
  90. pycforge_sdk/gui/visual/resources/icons/128/whitespace.png +0 -0
  91. pycforge_sdk/gui/visual/resources/icons/16/add-document.png +0 -0
  92. pycforge_sdk/gui/visual/resources/icons/16/brand-mark.png +0 -0
  93. pycforge_sdk/gui/visual/resources/icons/16/bundle-search.png +0 -0
  94. pycforge_sdk/gui/visual/resources/icons/16/cancel.png +0 -0
  95. pycforge_sdk/gui/visual/resources/icons/16/check.png +0 -0
  96. pycforge_sdk/gui/visual/resources/icons/16/chevron-right.png +0 -0
  97. pycforge_sdk/gui/visual/resources/icons/16/close.png +0 -0
  98. pycforge_sdk/gui/visual/resources/icons/16/collapse-all.png +0 -0
  99. pycforge_sdk/gui/visual/resources/icons/16/command-palette.png +0 -0
  100. pycforge_sdk/gui/visual/resources/icons/16/convert.png +0 -0
  101. pycforge_sdk/gui/visual/resources/icons/16/copy.png +0 -0
  102. pycforge_sdk/gui/visual/resources/icons/16/cut.png +0 -0
  103. pycforge_sdk/gui/visual/resources/icons/16/decision-trace.png +0 -0
  104. pycforge_sdk/gui/visual/resources/icons/16/details.png +0 -0
  105. pycforge_sdk/gui/visual/resources/icons/16/diagnostics.png +0 -0
  106. pycforge_sdk/gui/visual/resources/icons/16/duplicate-line.png +0 -0
  107. pycforge_sdk/gui/visual/resources/icons/16/exit.png +0 -0
  108. pycforge_sdk/gui/visual/resources/icons/16/expand-all.png +0 -0
  109. pycforge_sdk/gui/visual/resources/icons/16/export.png +0 -0
  110. pycforge_sdk/gui/visual/resources/icons/16/find.png +0 -0
  111. pycforge_sdk/gui/visual/resources/icons/16/go-to-line.png +0 -0
  112. pycforge_sdk/gui/visual/resources/icons/16/go-to-output.png +0 -0
  113. pycforge_sdk/gui/visual/resources/icons/16/go-to-source.png +0 -0
  114. pycforge_sdk/gui/visual/resources/icons/16/help.png +0 -0
  115. pycforge_sdk/gui/visual/resources/icons/16/history.png +0 -0
  116. pycforge_sdk/gui/visual/resources/icons/16/indent.png +0 -0
  117. pycforge_sdk/gui/visual/resources/icons/16/link-c.png +0 -0
  118. pycforge_sdk/gui/visual/resources/icons/16/mappings.png +0 -0
  119. pycforge_sdk/gui/visual/resources/icons/16/module.png +0 -0
  120. pycforge_sdk/gui/visual/resources/icons/16/move-down.png +0 -0
  121. pycforge_sdk/gui/visual/resources/icons/16/move-line-down.png +0 -0
  122. pycforge_sdk/gui/visual/resources/icons/16/move-line-up.png +0 -0
  123. pycforge_sdk/gui/visual/resources/icons/16/move-up.png +0 -0
  124. pycforge_sdk/gui/visual/resources/icons/16/next.png +0 -0
  125. pycforge_sdk/gui/visual/resources/icons/16/open.png +0 -0
  126. pycforge_sdk/gui/visual/resources/icons/16/outdent.png +0 -0
  127. pycforge_sdk/gui/visual/resources/icons/16/outline.png +0 -0
  128. pycforge_sdk/gui/visual/resources/icons/16/paste.png +0 -0
  129. pycforge_sdk/gui/visual/resources/icons/16/previous.png +0 -0
  130. pycforge_sdk/gui/visual/resources/icons/16/primary-module.png +0 -0
  131. pycforge_sdk/gui/visual/resources/icons/16/redo.png +0 -0
  132. pycforge_sdk/gui/visual/resources/icons/16/remove-document.png +0 -0
  133. pycforge_sdk/gui/visual/resources/icons/16/replace.png +0 -0
  134. pycforge_sdk/gui/visual/resources/icons/16/save-as.png +0 -0
  135. pycforge_sdk/gui/visual/resources/icons/16/save.png +0 -0
  136. pycforge_sdk/gui/visual/resources/icons/16/select-all.png +0 -0
  137. pycforge_sdk/gui/visual/resources/icons/16/settings.png +0 -0
  138. pycforge_sdk/gui/visual/resources/icons/16/show-c.png +0 -0
  139. pycforge_sdk/gui/visual/resources/icons/16/split-view.png +0 -0
  140. pycforge_sdk/gui/visual/resources/icons/16/summary.png +0 -0
  141. pycforge_sdk/gui/visual/resources/icons/16/telemetry.png +0 -0
  142. pycforge_sdk/gui/visual/resources/icons/16/toggle-comment.png +0 -0
  143. pycforge_sdk/gui/visual/resources/icons/16/toggle-fold.png +0 -0
  144. pycforge_sdk/gui/visual/resources/icons/16/tools.png +0 -0
  145. pycforge_sdk/gui/visual/resources/icons/16/undo.png +0 -0
  146. pycforge_sdk/gui/visual/resources/icons/16/whitespace.png +0 -0
  147. pycforge_sdk/gui/visual/resources/icons/20/add-document.png +0 -0
  148. pycforge_sdk/gui/visual/resources/icons/20/brand-mark.png +0 -0
  149. pycforge_sdk/gui/visual/resources/icons/20/bundle-search.png +0 -0
  150. pycforge_sdk/gui/visual/resources/icons/20/cancel.png +0 -0
  151. pycforge_sdk/gui/visual/resources/icons/20/check.png +0 -0
  152. pycforge_sdk/gui/visual/resources/icons/20/chevron-right.png +0 -0
  153. pycforge_sdk/gui/visual/resources/icons/20/close.png +0 -0
  154. pycforge_sdk/gui/visual/resources/icons/20/collapse-all.png +0 -0
  155. pycforge_sdk/gui/visual/resources/icons/20/command-palette.png +0 -0
  156. pycforge_sdk/gui/visual/resources/icons/20/convert.png +0 -0
  157. pycforge_sdk/gui/visual/resources/icons/20/copy.png +0 -0
  158. pycforge_sdk/gui/visual/resources/icons/20/cut.png +0 -0
  159. pycforge_sdk/gui/visual/resources/icons/20/decision-trace.png +0 -0
  160. pycforge_sdk/gui/visual/resources/icons/20/details.png +0 -0
  161. pycforge_sdk/gui/visual/resources/icons/20/diagnostics.png +0 -0
  162. pycforge_sdk/gui/visual/resources/icons/20/duplicate-line.png +0 -0
  163. pycforge_sdk/gui/visual/resources/icons/20/exit.png +0 -0
  164. pycforge_sdk/gui/visual/resources/icons/20/expand-all.png +0 -0
  165. pycforge_sdk/gui/visual/resources/icons/20/export.png +0 -0
  166. pycforge_sdk/gui/visual/resources/icons/20/find.png +0 -0
  167. pycforge_sdk/gui/visual/resources/icons/20/go-to-line.png +0 -0
  168. pycforge_sdk/gui/visual/resources/icons/20/go-to-output.png +0 -0
  169. pycforge_sdk/gui/visual/resources/icons/20/go-to-source.png +0 -0
  170. pycforge_sdk/gui/visual/resources/icons/20/help.png +0 -0
  171. pycforge_sdk/gui/visual/resources/icons/20/history.png +0 -0
  172. pycforge_sdk/gui/visual/resources/icons/20/indent.png +0 -0
  173. pycforge_sdk/gui/visual/resources/icons/20/link-c.png +0 -0
  174. pycforge_sdk/gui/visual/resources/icons/20/mappings.png +0 -0
  175. pycforge_sdk/gui/visual/resources/icons/20/module.png +0 -0
  176. pycforge_sdk/gui/visual/resources/icons/20/move-down.png +0 -0
  177. pycforge_sdk/gui/visual/resources/icons/20/move-line-down.png +0 -0
  178. pycforge_sdk/gui/visual/resources/icons/20/move-line-up.png +0 -0
  179. pycforge_sdk/gui/visual/resources/icons/20/move-up.png +0 -0
  180. pycforge_sdk/gui/visual/resources/icons/20/next.png +0 -0
  181. pycforge_sdk/gui/visual/resources/icons/20/open.png +0 -0
  182. pycforge_sdk/gui/visual/resources/icons/20/outdent.png +0 -0
  183. pycforge_sdk/gui/visual/resources/icons/20/outline.png +0 -0
  184. pycforge_sdk/gui/visual/resources/icons/20/paste.png +0 -0
  185. pycforge_sdk/gui/visual/resources/icons/20/previous.png +0 -0
  186. pycforge_sdk/gui/visual/resources/icons/20/primary-module.png +0 -0
  187. pycforge_sdk/gui/visual/resources/icons/20/redo.png +0 -0
  188. pycforge_sdk/gui/visual/resources/icons/20/remove-document.png +0 -0
  189. pycforge_sdk/gui/visual/resources/icons/20/replace.png +0 -0
  190. pycforge_sdk/gui/visual/resources/icons/20/save-as.png +0 -0
  191. pycforge_sdk/gui/visual/resources/icons/20/save.png +0 -0
  192. pycforge_sdk/gui/visual/resources/icons/20/select-all.png +0 -0
  193. pycforge_sdk/gui/visual/resources/icons/20/settings.png +0 -0
  194. pycforge_sdk/gui/visual/resources/icons/20/show-c.png +0 -0
  195. pycforge_sdk/gui/visual/resources/icons/20/split-view.png +0 -0
  196. pycforge_sdk/gui/visual/resources/icons/20/summary.png +0 -0
  197. pycforge_sdk/gui/visual/resources/icons/20/telemetry.png +0 -0
  198. pycforge_sdk/gui/visual/resources/icons/20/toggle-comment.png +0 -0
  199. pycforge_sdk/gui/visual/resources/icons/20/toggle-fold.png +0 -0
  200. pycforge_sdk/gui/visual/resources/icons/20/tools.png +0 -0
  201. pycforge_sdk/gui/visual/resources/icons/20/undo.png +0 -0
  202. pycforge_sdk/gui/visual/resources/icons/20/whitespace.png +0 -0
  203. pycforge_sdk/gui/visual/resources/icons/24/add-document.png +0 -0
  204. pycforge_sdk/gui/visual/resources/icons/24/brand-mark.png +0 -0
  205. pycforge_sdk/gui/visual/resources/icons/24/bundle-search.png +0 -0
  206. pycforge_sdk/gui/visual/resources/icons/24/cancel.png +0 -0
  207. pycforge_sdk/gui/visual/resources/icons/24/check.png +0 -0
  208. pycforge_sdk/gui/visual/resources/icons/24/chevron-right.png +0 -0
  209. pycforge_sdk/gui/visual/resources/icons/24/close.png +0 -0
  210. pycforge_sdk/gui/visual/resources/icons/24/collapse-all.png +0 -0
  211. pycforge_sdk/gui/visual/resources/icons/24/command-palette.png +0 -0
  212. pycforge_sdk/gui/visual/resources/icons/24/convert.png +0 -0
  213. pycforge_sdk/gui/visual/resources/icons/24/copy.png +0 -0
  214. pycforge_sdk/gui/visual/resources/icons/24/cut.png +0 -0
  215. pycforge_sdk/gui/visual/resources/icons/24/decision-trace.png +0 -0
  216. pycforge_sdk/gui/visual/resources/icons/24/details.png +0 -0
  217. pycforge_sdk/gui/visual/resources/icons/24/diagnostics.png +0 -0
  218. pycforge_sdk/gui/visual/resources/icons/24/duplicate-line.png +0 -0
  219. pycforge_sdk/gui/visual/resources/icons/24/exit.png +0 -0
  220. pycforge_sdk/gui/visual/resources/icons/24/expand-all.png +0 -0
  221. pycforge_sdk/gui/visual/resources/icons/24/export.png +0 -0
  222. pycforge_sdk/gui/visual/resources/icons/24/find.png +0 -0
  223. pycforge_sdk/gui/visual/resources/icons/24/go-to-line.png +0 -0
  224. pycforge_sdk/gui/visual/resources/icons/24/go-to-output.png +0 -0
  225. pycforge_sdk/gui/visual/resources/icons/24/go-to-source.png +0 -0
  226. pycforge_sdk/gui/visual/resources/icons/24/help.png +0 -0
  227. pycforge_sdk/gui/visual/resources/icons/24/history.png +0 -0
  228. pycforge_sdk/gui/visual/resources/icons/24/indent.png +0 -0
  229. pycforge_sdk/gui/visual/resources/icons/24/link-c.png +0 -0
  230. pycforge_sdk/gui/visual/resources/icons/24/mappings.png +0 -0
  231. pycforge_sdk/gui/visual/resources/icons/24/module.png +0 -0
  232. pycforge_sdk/gui/visual/resources/icons/24/move-down.png +0 -0
  233. pycforge_sdk/gui/visual/resources/icons/24/move-line-down.png +0 -0
  234. pycforge_sdk/gui/visual/resources/icons/24/move-line-up.png +0 -0
  235. pycforge_sdk/gui/visual/resources/icons/24/move-up.png +0 -0
  236. pycforge_sdk/gui/visual/resources/icons/24/next.png +0 -0
  237. pycforge_sdk/gui/visual/resources/icons/24/open.png +0 -0
  238. pycforge_sdk/gui/visual/resources/icons/24/outdent.png +0 -0
  239. pycforge_sdk/gui/visual/resources/icons/24/outline.png +0 -0
  240. pycforge_sdk/gui/visual/resources/icons/24/paste.png +0 -0
  241. pycforge_sdk/gui/visual/resources/icons/24/previous.png +0 -0
  242. pycforge_sdk/gui/visual/resources/icons/24/primary-module.png +0 -0
  243. pycforge_sdk/gui/visual/resources/icons/24/redo.png +0 -0
  244. pycforge_sdk/gui/visual/resources/icons/24/remove-document.png +0 -0
  245. pycforge_sdk/gui/visual/resources/icons/24/replace.png +0 -0
  246. pycforge_sdk/gui/visual/resources/icons/24/save-as.png +0 -0
  247. pycforge_sdk/gui/visual/resources/icons/24/save.png +0 -0
  248. pycforge_sdk/gui/visual/resources/icons/24/select-all.png +0 -0
  249. pycforge_sdk/gui/visual/resources/icons/24/settings.png +0 -0
  250. pycforge_sdk/gui/visual/resources/icons/24/show-c.png +0 -0
  251. pycforge_sdk/gui/visual/resources/icons/24/split-view.png +0 -0
  252. pycforge_sdk/gui/visual/resources/icons/24/summary.png +0 -0
  253. pycforge_sdk/gui/visual/resources/icons/24/telemetry.png +0 -0
  254. pycforge_sdk/gui/visual/resources/icons/24/toggle-comment.png +0 -0
  255. pycforge_sdk/gui/visual/resources/icons/24/toggle-fold.png +0 -0
  256. pycforge_sdk/gui/visual/resources/icons/24/tools.png +0 -0
  257. pycforge_sdk/gui/visual/resources/icons/24/undo.png +0 -0
  258. pycforge_sdk/gui/visual/resources/icons/24/whitespace.png +0 -0
  259. pycforge_sdk/gui/visual/resources/icons/256/add-document.png +0 -0
  260. pycforge_sdk/gui/visual/resources/icons/256/brand-mark.png +0 -0
  261. pycforge_sdk/gui/visual/resources/icons/256/bundle-search.png +0 -0
  262. pycforge_sdk/gui/visual/resources/icons/256/cancel.png +0 -0
  263. pycforge_sdk/gui/visual/resources/icons/256/check.png +0 -0
  264. pycforge_sdk/gui/visual/resources/icons/256/chevron-right.png +0 -0
  265. pycforge_sdk/gui/visual/resources/icons/256/close.png +0 -0
  266. pycforge_sdk/gui/visual/resources/icons/256/collapse-all.png +0 -0
  267. pycforge_sdk/gui/visual/resources/icons/256/command-palette.png +0 -0
  268. pycforge_sdk/gui/visual/resources/icons/256/convert.png +0 -0
  269. pycforge_sdk/gui/visual/resources/icons/256/copy.png +0 -0
  270. pycforge_sdk/gui/visual/resources/icons/256/cut.png +0 -0
  271. pycforge_sdk/gui/visual/resources/icons/256/decision-trace.png +0 -0
  272. pycforge_sdk/gui/visual/resources/icons/256/details.png +0 -0
  273. pycforge_sdk/gui/visual/resources/icons/256/diagnostics.png +0 -0
  274. pycforge_sdk/gui/visual/resources/icons/256/duplicate-line.png +0 -0
  275. pycforge_sdk/gui/visual/resources/icons/256/exit.png +0 -0
  276. pycforge_sdk/gui/visual/resources/icons/256/expand-all.png +0 -0
  277. pycforge_sdk/gui/visual/resources/icons/256/export.png +0 -0
  278. pycforge_sdk/gui/visual/resources/icons/256/find.png +0 -0
  279. pycforge_sdk/gui/visual/resources/icons/256/go-to-line.png +0 -0
  280. pycforge_sdk/gui/visual/resources/icons/256/go-to-output.png +0 -0
  281. pycforge_sdk/gui/visual/resources/icons/256/go-to-source.png +0 -0
  282. pycforge_sdk/gui/visual/resources/icons/256/help.png +0 -0
  283. pycforge_sdk/gui/visual/resources/icons/256/history.png +0 -0
  284. pycforge_sdk/gui/visual/resources/icons/256/indent.png +0 -0
  285. pycforge_sdk/gui/visual/resources/icons/256/link-c.png +0 -0
  286. pycforge_sdk/gui/visual/resources/icons/256/mappings.png +0 -0
  287. pycforge_sdk/gui/visual/resources/icons/256/module.png +0 -0
  288. pycforge_sdk/gui/visual/resources/icons/256/move-down.png +0 -0
  289. pycforge_sdk/gui/visual/resources/icons/256/move-line-down.png +0 -0
  290. pycforge_sdk/gui/visual/resources/icons/256/move-line-up.png +0 -0
  291. pycforge_sdk/gui/visual/resources/icons/256/move-up.png +0 -0
  292. pycforge_sdk/gui/visual/resources/icons/256/next.png +0 -0
  293. pycforge_sdk/gui/visual/resources/icons/256/open.png +0 -0
  294. pycforge_sdk/gui/visual/resources/icons/256/outdent.png +0 -0
  295. pycforge_sdk/gui/visual/resources/icons/256/outline.png +0 -0
  296. pycforge_sdk/gui/visual/resources/icons/256/paste.png +0 -0
  297. pycforge_sdk/gui/visual/resources/icons/256/previous.png +0 -0
  298. pycforge_sdk/gui/visual/resources/icons/256/primary-module.png +0 -0
  299. pycforge_sdk/gui/visual/resources/icons/256/redo.png +0 -0
  300. pycforge_sdk/gui/visual/resources/icons/256/remove-document.png +0 -0
  301. pycforge_sdk/gui/visual/resources/icons/256/replace.png +0 -0
  302. pycforge_sdk/gui/visual/resources/icons/256/save-as.png +0 -0
  303. pycforge_sdk/gui/visual/resources/icons/256/save.png +0 -0
  304. pycforge_sdk/gui/visual/resources/icons/256/select-all.png +0 -0
  305. pycforge_sdk/gui/visual/resources/icons/256/settings.png +0 -0
  306. pycforge_sdk/gui/visual/resources/icons/256/show-c.png +0 -0
  307. pycforge_sdk/gui/visual/resources/icons/256/split-view.png +0 -0
  308. pycforge_sdk/gui/visual/resources/icons/256/summary.png +0 -0
  309. pycforge_sdk/gui/visual/resources/icons/256/telemetry.png +0 -0
  310. pycforge_sdk/gui/visual/resources/icons/256/toggle-comment.png +0 -0
  311. pycforge_sdk/gui/visual/resources/icons/256/toggle-fold.png +0 -0
  312. pycforge_sdk/gui/visual/resources/icons/256/tools.png +0 -0
  313. pycforge_sdk/gui/visual/resources/icons/256/undo.png +0 -0
  314. pycforge_sdk/gui/visual/resources/icons/256/whitespace.png +0 -0
  315. pycforge_sdk/gui/visual/resources/icons/32/add-document.png +0 -0
  316. pycforge_sdk/gui/visual/resources/icons/32/brand-mark.png +0 -0
  317. pycforge_sdk/gui/visual/resources/icons/32/bundle-search.png +0 -0
  318. pycforge_sdk/gui/visual/resources/icons/32/cancel.png +0 -0
  319. pycforge_sdk/gui/visual/resources/icons/32/check.png +0 -0
  320. pycforge_sdk/gui/visual/resources/icons/32/chevron-right.png +0 -0
  321. pycforge_sdk/gui/visual/resources/icons/32/close.png +0 -0
  322. pycforge_sdk/gui/visual/resources/icons/32/collapse-all.png +0 -0
  323. pycforge_sdk/gui/visual/resources/icons/32/command-palette.png +0 -0
  324. pycforge_sdk/gui/visual/resources/icons/32/convert.png +0 -0
  325. pycforge_sdk/gui/visual/resources/icons/32/copy.png +0 -0
  326. pycforge_sdk/gui/visual/resources/icons/32/cut.png +0 -0
  327. pycforge_sdk/gui/visual/resources/icons/32/decision-trace.png +0 -0
  328. pycforge_sdk/gui/visual/resources/icons/32/details.png +0 -0
  329. pycforge_sdk/gui/visual/resources/icons/32/diagnostics.png +0 -0
  330. pycforge_sdk/gui/visual/resources/icons/32/duplicate-line.png +0 -0
  331. pycforge_sdk/gui/visual/resources/icons/32/exit.png +0 -0
  332. pycforge_sdk/gui/visual/resources/icons/32/expand-all.png +0 -0
  333. pycforge_sdk/gui/visual/resources/icons/32/export.png +0 -0
  334. pycforge_sdk/gui/visual/resources/icons/32/find.png +0 -0
  335. pycforge_sdk/gui/visual/resources/icons/32/go-to-line.png +0 -0
  336. pycforge_sdk/gui/visual/resources/icons/32/go-to-output.png +0 -0
  337. pycforge_sdk/gui/visual/resources/icons/32/go-to-source.png +0 -0
  338. pycforge_sdk/gui/visual/resources/icons/32/help.png +0 -0
  339. pycforge_sdk/gui/visual/resources/icons/32/history.png +0 -0
  340. pycforge_sdk/gui/visual/resources/icons/32/indent.png +0 -0
  341. pycforge_sdk/gui/visual/resources/icons/32/link-c.png +0 -0
  342. pycforge_sdk/gui/visual/resources/icons/32/mappings.png +0 -0
  343. pycforge_sdk/gui/visual/resources/icons/32/module.png +0 -0
  344. pycforge_sdk/gui/visual/resources/icons/32/move-down.png +0 -0
  345. pycforge_sdk/gui/visual/resources/icons/32/move-line-down.png +0 -0
  346. pycforge_sdk/gui/visual/resources/icons/32/move-line-up.png +0 -0
  347. pycforge_sdk/gui/visual/resources/icons/32/move-up.png +0 -0
  348. pycforge_sdk/gui/visual/resources/icons/32/next.png +0 -0
  349. pycforge_sdk/gui/visual/resources/icons/32/open.png +0 -0
  350. pycforge_sdk/gui/visual/resources/icons/32/outdent.png +0 -0
  351. pycforge_sdk/gui/visual/resources/icons/32/outline.png +0 -0
  352. pycforge_sdk/gui/visual/resources/icons/32/paste.png +0 -0
  353. pycforge_sdk/gui/visual/resources/icons/32/previous.png +0 -0
  354. pycforge_sdk/gui/visual/resources/icons/32/primary-module.png +0 -0
  355. pycforge_sdk/gui/visual/resources/icons/32/redo.png +0 -0
  356. pycforge_sdk/gui/visual/resources/icons/32/remove-document.png +0 -0
  357. pycforge_sdk/gui/visual/resources/icons/32/replace.png +0 -0
  358. pycforge_sdk/gui/visual/resources/icons/32/save-as.png +0 -0
  359. pycforge_sdk/gui/visual/resources/icons/32/save.png +0 -0
  360. pycforge_sdk/gui/visual/resources/icons/32/select-all.png +0 -0
  361. pycforge_sdk/gui/visual/resources/icons/32/settings.png +0 -0
  362. pycforge_sdk/gui/visual/resources/icons/32/show-c.png +0 -0
  363. pycforge_sdk/gui/visual/resources/icons/32/split-view.png +0 -0
  364. pycforge_sdk/gui/visual/resources/icons/32/summary.png +0 -0
  365. pycforge_sdk/gui/visual/resources/icons/32/telemetry.png +0 -0
  366. pycforge_sdk/gui/visual/resources/icons/32/toggle-comment.png +0 -0
  367. pycforge_sdk/gui/visual/resources/icons/32/toggle-fold.png +0 -0
  368. pycforge_sdk/gui/visual/resources/icons/32/tools.png +0 -0
  369. pycforge_sdk/gui/visual/resources/icons/32/undo.png +0 -0
  370. pycforge_sdk/gui/visual/resources/icons/32/whitespace.png +0 -0
  371. pycforge_sdk/gui/visual/resources/icons/48/add-document.png +0 -0
  372. pycforge_sdk/gui/visual/resources/icons/48/brand-mark.png +0 -0
  373. pycforge_sdk/gui/visual/resources/icons/48/bundle-search.png +0 -0
  374. pycforge_sdk/gui/visual/resources/icons/48/cancel.png +0 -0
  375. pycforge_sdk/gui/visual/resources/icons/48/check.png +0 -0
  376. pycforge_sdk/gui/visual/resources/icons/48/chevron-right.png +0 -0
  377. pycforge_sdk/gui/visual/resources/icons/48/close.png +0 -0
  378. pycforge_sdk/gui/visual/resources/icons/48/collapse-all.png +0 -0
  379. pycforge_sdk/gui/visual/resources/icons/48/command-palette.png +0 -0
  380. pycforge_sdk/gui/visual/resources/icons/48/convert.png +0 -0
  381. pycforge_sdk/gui/visual/resources/icons/48/copy.png +0 -0
  382. pycforge_sdk/gui/visual/resources/icons/48/cut.png +0 -0
  383. pycforge_sdk/gui/visual/resources/icons/48/decision-trace.png +0 -0
  384. pycforge_sdk/gui/visual/resources/icons/48/details.png +0 -0
  385. pycforge_sdk/gui/visual/resources/icons/48/diagnostics.png +0 -0
  386. pycforge_sdk/gui/visual/resources/icons/48/duplicate-line.png +0 -0
  387. pycforge_sdk/gui/visual/resources/icons/48/exit.png +0 -0
  388. pycforge_sdk/gui/visual/resources/icons/48/expand-all.png +0 -0
  389. pycforge_sdk/gui/visual/resources/icons/48/export.png +0 -0
  390. pycforge_sdk/gui/visual/resources/icons/48/find.png +0 -0
  391. pycforge_sdk/gui/visual/resources/icons/48/go-to-line.png +0 -0
  392. pycforge_sdk/gui/visual/resources/icons/48/go-to-output.png +0 -0
  393. pycforge_sdk/gui/visual/resources/icons/48/go-to-source.png +0 -0
  394. pycforge_sdk/gui/visual/resources/icons/48/help.png +0 -0
  395. pycforge_sdk/gui/visual/resources/icons/48/history.png +0 -0
  396. pycforge_sdk/gui/visual/resources/icons/48/indent.png +0 -0
  397. pycforge_sdk/gui/visual/resources/icons/48/link-c.png +0 -0
  398. pycforge_sdk/gui/visual/resources/icons/48/mappings.png +0 -0
  399. pycforge_sdk/gui/visual/resources/icons/48/module.png +0 -0
  400. pycforge_sdk/gui/visual/resources/icons/48/move-down.png +0 -0
  401. pycforge_sdk/gui/visual/resources/icons/48/move-line-down.png +0 -0
  402. pycforge_sdk/gui/visual/resources/icons/48/move-line-up.png +0 -0
  403. pycforge_sdk/gui/visual/resources/icons/48/move-up.png +0 -0
  404. pycforge_sdk/gui/visual/resources/icons/48/next.png +0 -0
  405. pycforge_sdk/gui/visual/resources/icons/48/open.png +0 -0
  406. pycforge_sdk/gui/visual/resources/icons/48/outdent.png +0 -0
  407. pycforge_sdk/gui/visual/resources/icons/48/outline.png +0 -0
  408. pycforge_sdk/gui/visual/resources/icons/48/paste.png +0 -0
  409. pycforge_sdk/gui/visual/resources/icons/48/previous.png +0 -0
  410. pycforge_sdk/gui/visual/resources/icons/48/primary-module.png +0 -0
  411. pycforge_sdk/gui/visual/resources/icons/48/redo.png +0 -0
  412. pycforge_sdk/gui/visual/resources/icons/48/remove-document.png +0 -0
  413. pycforge_sdk/gui/visual/resources/icons/48/replace.png +0 -0
  414. pycforge_sdk/gui/visual/resources/icons/48/save-as.png +0 -0
  415. pycforge_sdk/gui/visual/resources/icons/48/save.png +0 -0
  416. pycforge_sdk/gui/visual/resources/icons/48/select-all.png +0 -0
  417. pycforge_sdk/gui/visual/resources/icons/48/settings.png +0 -0
  418. pycforge_sdk/gui/visual/resources/icons/48/show-c.png +0 -0
  419. pycforge_sdk/gui/visual/resources/icons/48/split-view.png +0 -0
  420. pycforge_sdk/gui/visual/resources/icons/48/summary.png +0 -0
  421. pycforge_sdk/gui/visual/resources/icons/48/telemetry.png +0 -0
  422. pycforge_sdk/gui/visual/resources/icons/48/toggle-comment.png +0 -0
  423. pycforge_sdk/gui/visual/resources/icons/48/toggle-fold.png +0 -0
  424. pycforge_sdk/gui/visual/resources/icons/48/tools.png +0 -0
  425. pycforge_sdk/gui/visual/resources/icons/48/undo.png +0 -0
  426. pycforge_sdk/gui/visual/resources/icons/48/whitespace.png +0 -0
  427. pycforge_sdk/gui/visual/resources/icons/64/add-document.png +0 -0
  428. pycforge_sdk/gui/visual/resources/icons/64/brand-mark.png +0 -0
  429. pycforge_sdk/gui/visual/resources/icons/64/bundle-search.png +0 -0
  430. pycforge_sdk/gui/visual/resources/icons/64/cancel.png +0 -0
  431. pycforge_sdk/gui/visual/resources/icons/64/check.png +0 -0
  432. pycforge_sdk/gui/visual/resources/icons/64/chevron-right.png +0 -0
  433. pycforge_sdk/gui/visual/resources/icons/64/close.png +0 -0
  434. pycforge_sdk/gui/visual/resources/icons/64/collapse-all.png +0 -0
  435. pycforge_sdk/gui/visual/resources/icons/64/command-palette.png +0 -0
  436. pycforge_sdk/gui/visual/resources/icons/64/convert.png +0 -0
  437. pycforge_sdk/gui/visual/resources/icons/64/copy.png +0 -0
  438. pycforge_sdk/gui/visual/resources/icons/64/cut.png +0 -0
  439. pycforge_sdk/gui/visual/resources/icons/64/decision-trace.png +0 -0
  440. pycforge_sdk/gui/visual/resources/icons/64/details.png +0 -0
  441. pycforge_sdk/gui/visual/resources/icons/64/diagnostics.png +0 -0
  442. pycforge_sdk/gui/visual/resources/icons/64/duplicate-line.png +0 -0
  443. pycforge_sdk/gui/visual/resources/icons/64/exit.png +0 -0
  444. pycforge_sdk/gui/visual/resources/icons/64/expand-all.png +0 -0
  445. pycforge_sdk/gui/visual/resources/icons/64/export.png +0 -0
  446. pycforge_sdk/gui/visual/resources/icons/64/find.png +0 -0
  447. pycforge_sdk/gui/visual/resources/icons/64/go-to-line.png +0 -0
  448. pycforge_sdk/gui/visual/resources/icons/64/go-to-output.png +0 -0
  449. pycforge_sdk/gui/visual/resources/icons/64/go-to-source.png +0 -0
  450. pycforge_sdk/gui/visual/resources/icons/64/help.png +0 -0
  451. pycforge_sdk/gui/visual/resources/icons/64/history.png +0 -0
  452. pycforge_sdk/gui/visual/resources/icons/64/indent.png +0 -0
  453. pycforge_sdk/gui/visual/resources/icons/64/link-c.png +0 -0
  454. pycforge_sdk/gui/visual/resources/icons/64/mappings.png +0 -0
  455. pycforge_sdk/gui/visual/resources/icons/64/module.png +0 -0
  456. pycforge_sdk/gui/visual/resources/icons/64/move-down.png +0 -0
  457. pycforge_sdk/gui/visual/resources/icons/64/move-line-down.png +0 -0
  458. pycforge_sdk/gui/visual/resources/icons/64/move-line-up.png +0 -0
  459. pycforge_sdk/gui/visual/resources/icons/64/move-up.png +0 -0
  460. pycforge_sdk/gui/visual/resources/icons/64/next.png +0 -0
  461. pycforge_sdk/gui/visual/resources/icons/64/open.png +0 -0
  462. pycforge_sdk/gui/visual/resources/icons/64/outdent.png +0 -0
  463. pycforge_sdk/gui/visual/resources/icons/64/outline.png +0 -0
  464. pycforge_sdk/gui/visual/resources/icons/64/paste.png +0 -0
  465. pycforge_sdk/gui/visual/resources/icons/64/previous.png +0 -0
  466. pycforge_sdk/gui/visual/resources/icons/64/primary-module.png +0 -0
  467. pycforge_sdk/gui/visual/resources/icons/64/redo.png +0 -0
  468. pycforge_sdk/gui/visual/resources/icons/64/remove-document.png +0 -0
  469. pycforge_sdk/gui/visual/resources/icons/64/replace.png +0 -0
  470. pycforge_sdk/gui/visual/resources/icons/64/save-as.png +0 -0
  471. pycforge_sdk/gui/visual/resources/icons/64/save.png +0 -0
  472. pycforge_sdk/gui/visual/resources/icons/64/select-all.png +0 -0
  473. pycforge_sdk/gui/visual/resources/icons/64/settings.png +0 -0
  474. pycforge_sdk/gui/visual/resources/icons/64/show-c.png +0 -0
  475. pycforge_sdk/gui/visual/resources/icons/64/split-view.png +0 -0
  476. pycforge_sdk/gui/visual/resources/icons/64/summary.png +0 -0
  477. pycforge_sdk/gui/visual/resources/icons/64/telemetry.png +0 -0
  478. pycforge_sdk/gui/visual/resources/icons/64/toggle-comment.png +0 -0
  479. pycforge_sdk/gui/visual/resources/icons/64/toggle-fold.png +0 -0
  480. pycforge_sdk/gui/visual/resources/icons/64/tools.png +0 -0
  481. pycforge_sdk/gui/visual/resources/icons/64/undo.png +0 -0
  482. pycforge_sdk/gui/visual/resources/icons/64/whitespace.png +0 -0
  483. pycforge_sdk/gui/visual/resources/icons/96/add-document.png +0 -0
  484. pycforge_sdk/gui/visual/resources/icons/96/brand-mark.png +0 -0
  485. pycforge_sdk/gui/visual/resources/icons/96/bundle-search.png +0 -0
  486. pycforge_sdk/gui/visual/resources/icons/96/cancel.png +0 -0
  487. pycforge_sdk/gui/visual/resources/icons/96/check.png +0 -0
  488. pycforge_sdk/gui/visual/resources/icons/96/chevron-right.png +0 -0
  489. pycforge_sdk/gui/visual/resources/icons/96/close.png +0 -0
  490. pycforge_sdk/gui/visual/resources/icons/96/collapse-all.png +0 -0
  491. pycforge_sdk/gui/visual/resources/icons/96/command-palette.png +0 -0
  492. pycforge_sdk/gui/visual/resources/icons/96/convert.png +0 -0
  493. pycforge_sdk/gui/visual/resources/icons/96/copy.png +0 -0
  494. pycforge_sdk/gui/visual/resources/icons/96/cut.png +0 -0
  495. pycforge_sdk/gui/visual/resources/icons/96/decision-trace.png +0 -0
  496. pycforge_sdk/gui/visual/resources/icons/96/details.png +0 -0
  497. pycforge_sdk/gui/visual/resources/icons/96/diagnostics.png +0 -0
  498. pycforge_sdk/gui/visual/resources/icons/96/duplicate-line.png +0 -0
  499. pycforge_sdk/gui/visual/resources/icons/96/exit.png +0 -0
  500. pycforge_sdk/gui/visual/resources/icons/96/expand-all.png +0 -0
  501. pycforge_sdk/gui/visual/resources/icons/96/export.png +0 -0
  502. pycforge_sdk/gui/visual/resources/icons/96/find.png +0 -0
  503. pycforge_sdk/gui/visual/resources/icons/96/go-to-line.png +0 -0
  504. pycforge_sdk/gui/visual/resources/icons/96/go-to-output.png +0 -0
  505. pycforge_sdk/gui/visual/resources/icons/96/go-to-source.png +0 -0
  506. pycforge_sdk/gui/visual/resources/icons/96/help.png +0 -0
  507. pycforge_sdk/gui/visual/resources/icons/96/history.png +0 -0
  508. pycforge_sdk/gui/visual/resources/icons/96/indent.png +0 -0
  509. pycforge_sdk/gui/visual/resources/icons/96/link-c.png +0 -0
  510. pycforge_sdk/gui/visual/resources/icons/96/mappings.png +0 -0
  511. pycforge_sdk/gui/visual/resources/icons/96/module.png +0 -0
  512. pycforge_sdk/gui/visual/resources/icons/96/move-down.png +0 -0
  513. pycforge_sdk/gui/visual/resources/icons/96/move-line-down.png +0 -0
  514. pycforge_sdk/gui/visual/resources/icons/96/move-line-up.png +0 -0
  515. pycforge_sdk/gui/visual/resources/icons/96/move-up.png +0 -0
  516. pycforge_sdk/gui/visual/resources/icons/96/next.png +0 -0
  517. pycforge_sdk/gui/visual/resources/icons/96/open.png +0 -0
  518. pycforge_sdk/gui/visual/resources/icons/96/outdent.png +0 -0
  519. pycforge_sdk/gui/visual/resources/icons/96/outline.png +0 -0
  520. pycforge_sdk/gui/visual/resources/icons/96/paste.png +0 -0
  521. pycforge_sdk/gui/visual/resources/icons/96/previous.png +0 -0
  522. pycforge_sdk/gui/visual/resources/icons/96/primary-module.png +0 -0
  523. pycforge_sdk/gui/visual/resources/icons/96/redo.png +0 -0
  524. pycforge_sdk/gui/visual/resources/icons/96/remove-document.png +0 -0
  525. pycforge_sdk/gui/visual/resources/icons/96/replace.png +0 -0
  526. pycforge_sdk/gui/visual/resources/icons/96/save-as.png +0 -0
  527. pycforge_sdk/gui/visual/resources/icons/96/save.png +0 -0
  528. pycforge_sdk/gui/visual/resources/icons/96/select-all.png +0 -0
  529. pycforge_sdk/gui/visual/resources/icons/96/settings.png +0 -0
  530. pycforge_sdk/gui/visual/resources/icons/96/show-c.png +0 -0
  531. pycforge_sdk/gui/visual/resources/icons/96/split-view.png +0 -0
  532. pycforge_sdk/gui/visual/resources/icons/96/summary.png +0 -0
  533. pycforge_sdk/gui/visual/resources/icons/96/telemetry.png +0 -0
  534. pycforge_sdk/gui/visual/resources/icons/96/toggle-comment.png +0 -0
  535. pycforge_sdk/gui/visual/resources/icons/96/toggle-fold.png +0 -0
  536. pycforge_sdk/gui/visual/resources/icons/96/tools.png +0 -0
  537. pycforge_sdk/gui/visual/resources/icons/96/undo.png +0 -0
  538. pycforge_sdk/gui/visual/resources/icons/96/whitespace.png +0 -0
  539. pycforge_sdk/gui/visual/theme.py +204 -0
  540. pycforge_sdk/gui/visual/theme_steel_stylesheet.py +901 -0
  541. pycforge_sdk/gui/visual/theme_stylesheet.py +597 -0
  542. pycforge_sdk/gui/visual/theme_workspace_stylesheet.py +169 -0
  543. pycforge_sdk/gui/visual/visual_tokens.py +146 -0
  544. pycforge_sdk/gui/widgets.py +68 -0
  545. pycforge_sdk/gui/window.py +559 -0
  546. pycforge_sdk/native.py +42 -0
  547. pycforge_sdk/package_metadata.py +21 -0
  548. pycforge_sdk/process.py +58 -0
  549. pycforge_sdk/project.py +143 -0
  550. pycforge_sdk/readiness.py +106 -0
  551. pycforge_sdk/results.py +45 -0
  552. pycforge_sdk/service.py +454 -0
  553. pycforge_sdk/workbench.py +88 -0
  554. pycforge_sdk-0.6.3.dist-info/METADATA +221 -0
  555. pycforge_sdk-0.6.3.dist-info/RECORD +559 -0
  556. pycforge_sdk-0.6.3.dist-info/WHEEL +5 -0
  557. pycforge_sdk-0.6.3.dist-info/entry_points.txt +5 -0
  558. pycforge_sdk-0.6.3.dist-info/licenses/LICENSE +674 -0
  559. pycforge_sdk-0.6.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,454 @@
1
+ """Public headless SDK: the console and optional PySide6 UI share this service."""
2
+ from __future__ import annotations
3
+ import base64
4
+ from datetime import date
5
+ from pathlib import Path
6
+ import tempfile
7
+ from .connection import Connection
8
+ from .native import compiler_identity, execute_fixture
9
+ from .project import Project, PROJECT_SCHEMA, DOCUMENTED_PROJECT_SCHEMA, REPORT_SCHEMA, MAX_PROJECT, atomic_write, canonical, digest, parse, read
10
+ from .results import SDK_VERSION, Outcome, SDKError, operation
11
+
12
+
13
+ class SDK:
14
+ """Select an installed engine and author extensions through its public API.
15
+
16
+ Construction performs no discovery, execution or file writes. Each instance
17
+ is a single-client session. Pass a threading.Event as cancel; progress is a
18
+ callable receiving detached dictionaries on the calling thread. A GUI should
19
+ run long operations in its own worker and forward those events to its UI.
20
+ """
21
+ def __init__(self, *, engine_python, cache, timeout=30, cancel=None, progress=None):
22
+ self._connection = Connection(engine_python, cache, timeout=timeout, cancel=cancel)
23
+ self.timeout, self.cancel, self.progress = timeout, cancel, progress
24
+
25
+ def _notify(self, phase, **data):
26
+ if self.cancel is not None and self.cancel.is_set():
27
+ raise SDKError("SDK_CANCELED", "Operation canceled.", status="canceled")
28
+ if self.progress is not None:
29
+ self.progress({"schema": "pycforge-sdk.progress/0.1", "phase": phase, **data})
30
+
31
+ @operation
32
+ def connect(self, *, offline=False) -> Outcome:
33
+ """Discover and refresh; failed connections retain labeled offline metadata."""
34
+ info = self._connection.connect(offline=offline)
35
+ return Outcome("succeeded" if info["state"] == "connected" else "incomplete", info)
36
+
37
+ @operation
38
+ def methods(self, *, advanced: bool = False) -> Outcome:
39
+ """Return grouped method-tree data without importing or executing examples."""
40
+ snapshot = self._connection.metadata()
41
+ if advanced:
42
+ return {"connection": self._connection.description(), "methods": list(snapshot.methods)}
43
+ guide = self._connection.reference()
44
+ return {"connection": self._connection.description(), "categories": guide["categories"],
45
+ "methods": guide["entries"], "limits": guide["limits"],
46
+ "domain_contracts": guide.get("domain_contracts", {}),
47
+ "documentation": guide.get("documentation", {}),
48
+ "workflow": guide.get("workflow", []), "array_operations": guide.get("array_operations", []),
49
+ "supported_profiles": guide.get("supported_profiles", [guide["profile"]])}
50
+
51
+ @operation
52
+ def workbench(self) -> Outcome:
53
+ """Read engine-owned forms, default imports and inert Help for every client."""
54
+ value = self._connection.workbench()
55
+ return {"connection": self._connection.description(), "workbench": value["definition"] if value else None,
56
+ "documents": value["documents"] if value else [], "source": "engine" if value else "legacy"}
57
+
58
+ @operation
59
+ def templates(self) -> Outcome:
60
+ """List small engine-owned starter cards; never execute template sources."""
61
+ guide = self._connection.reference()
62
+ return {"connection": self._connection.description(),
63
+ "templates": [{"id": t["id"], "title": t["title"], "description": t["description"],
64
+ "declaration_schema": t["declaration"]["schema"]} for t in guide["templates"]],
65
+ "workflow": guide.get("workflow", []), "limits": guide["limits"]}
66
+
67
+ @operation
68
+ def describe(self, method: str) -> Outcome:
69
+ """Explain one supported authoring method, including parameters and examples."""
70
+ entries = self._connection.reference()["entries"]
71
+ selected = [entry for entry in entries if entry["id"] == method or entry["id"].endswith("." + method)]
72
+ if len(selected) != 1:
73
+ raise SDKError("SDK_METHOD", "Choose one exact method from the authoring tree.")
74
+ return {"connection": self._connection.description(), "method": selected[0],
75
+ "domain_contracts": self._connection.reference().get("domain_contracts", {}),
76
+ "array_operations": self._connection.reference().get("array_operations", []) if method.endswith("ArrayFunction") else []}
77
+
78
+ @operation
79
+ def create_project(self, directory: str | Path, *, author: str, template: str = "scalar-cube-root") -> Outcome:
80
+ """Create a data-only starter project from engine-provided template data."""
81
+ guide = self._connection.reference()
82
+ choices = [item for item in guide["templates"] if item.get("id") == template]
83
+ if len(choices) != 1:
84
+ raise SDKError("SDK_TEMPLATE", "Unknown or ambiguous engine template.")
85
+ selected = choices[0]
86
+ destination = Path(directory).absolute()
87
+ if destination.exists() or destination.is_symlink():
88
+ raise SDKError("SDK_EXISTS", "Project destination already exists; no files were changed.")
89
+ if type(author) is not str or not author.strip():
90
+ raise SDKError("SDK_ARGUMENT", "An author name is required.")
91
+ destination.parent.mkdir(parents=True, exist_ok=True)
92
+ with tempfile.TemporaryDirectory(prefix=".sdk-project-", dir=destination.parent) as temporary:
93
+ stage = Path(temporary)/"project"
94
+ (stage/"tests").mkdir(parents=True)
95
+ cases = []
96
+ for i,case in enumerate(selected["cases"]):
97
+ filename = f"tests/case_{i+1}.py"
98
+ (stage/filename).write_text(case["source"], encoding="utf-8", newline="\n")
99
+ cases.append({"name": case["name"], "file": filename, "expect": case["expect"]})
100
+ document = {"schema": PROJECT_SCHEMA, "declaration": selected["declaration"],
101
+ "metadata": {"author": author, "created": date.today().isoformat(),
102
+ "description": selected["description"], "license": "GPL-3.0-only"}, "cases": cases}
103
+ if guide.get("documentation", {}).get("schema") == "pycforge.extension-help/0.1":
104
+ document["schema"] = DOCUMENTED_PROJECT_SCHEMA
105
+ document["documentation"] = selected.get("documentation")
106
+ (stage/"project.json").write_bytes(canonical(document))
107
+ Project.load(stage)
108
+ stage.rename(destination)
109
+ project = Project.load(destination)
110
+ return {"directory": str(destination), "project_sha256": project.sha256,
111
+ "verification": "not-established", "connection": self._connection.description()}
112
+
113
+ @operation
114
+ def inspect(self, directory: str | Path) -> Outcome:
115
+ """Ask the engine to inspect the exact saved declaration; never run tests."""
116
+ project = Project.load(directory)
117
+ result = self._connection.call("inspect", {"declaration": project.document["declaration"]})
118
+ project.ensure_current()
119
+ return {"project_sha256": project.sha256, "inspection": result}
120
+
121
+ def _documentation_capability(self):
122
+ guide = self._connection.reference()
123
+ if guide.get("documentation", {}).get("schema") != "pycforge.extension-help/0.1":
124
+ raise SDKError("SDK_CAPABILITY", "Documented builds require PyCForge 1.3.64 or a compatible engine advertising extension-help/0.1. Existing project files were not changed.")
125
+
126
+ def _scan(self, project):
127
+ self._documentation_capability()
128
+ document = project.document
129
+ result = self._connection.call("scan", {"declaration": document["declaration"],
130
+ "documentation": document.get("documentation")})
131
+ issues = list(result["issues"])
132
+ if not issues:
133
+ cases = {case["name"]: case for case in document["cases"]}
134
+ for export, item in document["documentation"]["functions"].items():
135
+ case = cases.get(item["example"])
136
+ if case is None or case["expect"]["kind"] != "run":
137
+ issues.append({"code": "SDK_DOCUMENTATION_EXAMPLE", "path": "/documentation/functions/" + export + "/example",
138
+ "message": "Choose an existing native run fixture; rejected-source cases cannot be Help examples.",
139
+ "remedy": "Add the fixture or select a run case from this project."})
140
+ if not issues:
141
+ bounded = self._connection.call("scan", {"declaration": document["declaration"],
142
+ "documentation": document["documentation"], "examples": self._examples(project)})
143
+ issues.extend(bounded["issues"])
144
+ project.ensure_current()
145
+ return {"schema": "pycforge-sdk.scan/0.1", "project_sha256": project.sha256,
146
+ "engine": dict(self._connection.snapshot.identity), "reference": result["reference"],
147
+ "template": result["template"], "coverage": result["coverage"], "issues": issues,
148
+ "state": "needs-authoring" if issues else "ready-to-verify",
149
+ "verification": "not-run", "checks": [
150
+ {"id": "declaration", "status": "passed"},
151
+ {"id": "documentation", "status": "incomplete" if result["issues"] else "passed"},
152
+ {"id": "example-links", "status": "incomplete" if issues else "passed"},
153
+ {"id": "native-verification", "status": "not-run"}]}
154
+
155
+ @operation
156
+ def scan(self, directory: str | Path) -> Outcome:
157
+ """Return a versioned readiness object and field locations; never run tests."""
158
+ result = self._scan(Project.load(directory))
159
+ return Outcome("rejected" if result["issues"] else "succeeded", {"scan": result}, tuple(result["issues"]))
160
+
161
+ @operation
162
+ def prepare_documentation(self, directory: str | Path) -> Outcome:
163
+ """Explicitly add missing author fields, preserving all existing prose.
164
+
165
+ Legacy projects are upgraded atomically to project/0.2. Generated blank
166
+ fields remain incomplete until the author supplies meaningful content.
167
+ Removed exports and changed argument meanings require explicit editing.
168
+ """
169
+ self._documentation_capability()
170
+ project = Project.load(directory)
171
+ document = project.document
172
+ result = self._connection.call("scan", {"declaration": document["declaration"]})
173
+ def fill(current, defaults):
174
+ if type(current) is dict and type(defaults) is dict:
175
+ return {**current, **{key: fill(current[key], value) if key in current else value
176
+ for key, value in defaults.items()}}
177
+ if type(current) is list and type(defaults) is list and len(current) < len(defaults):
178
+ return current + defaults[len(current):]
179
+ return current
180
+ existing = document.get("documentation")
181
+ document["documentation"] = result["template"] if existing is None else fill(existing, result["template"])
182
+ document["schema"] = DOCUMENTED_PROJECT_SCHEMA
183
+ project.ensure_current()
184
+ output = canonical(document)
185
+ if len(output) + sum(len(content) for _, content in project.sources) > MAX_PROJECT:
186
+ raise SDKError("SDK_PROJECT", "Documentation scaffolding would exceed the 4 MiB project budget; no files were changed.")
187
+ if output != project.document_bytes:
188
+ atomic_write(project.root / "project.json", output)
189
+ updated = Project.load(directory)
190
+ return {"project_sha256": updated.sha256, "changed": updated.sha256 != project.sha256,
191
+ "document": str(updated.root / "project.json"), "verification": "not-established",
192
+ "next": "Fill the author fields, run scan, then verify and build."}
193
+
194
+ @staticmethod
195
+ def _examples(project):
196
+ document = project.document
197
+ names = {item["example"] for item in document["documentation"]["functions"].values()}
198
+ sources = dict(project.sources)
199
+ return [{"name": case["name"], "source": sources[case["file"]].decode("utf-8"),
200
+ **{k: case["expect"][k] for k in ("stdout", "stderr", "exit_code")}}
201
+ for case in sorted(document["cases"], key=lambda c: c["name"]) if case["name"] in names]
202
+
203
+ @staticmethod
204
+ def _documentation_coverage(project, inspection, cases):
205
+ by_name = {case["name"]: case for case in cases}
206
+ missing = []
207
+ for function in inspection["extension"]["functions"]:
208
+ example = project.document["documentation"]["functions"][function["export"]]["example"]
209
+ case = by_name.get(example)
210
+ if (case is None or case.get("passed") is not True or case["expected"]["kind"] != "run"
211
+ or function["operation_id"] not in case.get("operations_used", [])):
212
+ missing.append(function["export"])
213
+ return {"kind": "documented-source-call-coverage", "missing": sorted(missing),
214
+ "scope": "Each Help example names a passing native fixture containing the documented operation; not dynamic branch or all-input coverage."}
215
+
216
+ @operation
217
+ def convert(self, directory: str | Path, case: str) -> Outcome:
218
+ """Convert a named fixture without compiling, executing or registering it."""
219
+ project = Project.load(directory)
220
+ cases = [item for item in project.document["cases"] if item["name"] == case]
221
+ if len(cases) != 1:
222
+ raise SDKError("SDK_CASE", "Unknown fixture name.")
223
+ result = self._convert(project, cases[0])
224
+ project.ensure_current()
225
+ status = "succeeded" if result.get("generated_c") else {
226
+ "Rejected": "rejected", "Canceled": "canceled", "InternalFailure": "internal_failure"}.get(result.get("status"), "incomplete")
227
+ return Outcome(status, {"project_sha256": project.sha256, "conversion": result})
228
+
229
+ def _convert(self, project, case):
230
+ source = dict(project.sources)[case["file"]].decode("utf-8")
231
+ return self._connection.call("convert", {"declaration": project.document["declaration"],
232
+ "source": source, "logical_name": case["file"]})
233
+
234
+ @operation
235
+ def verify(self, directory: str | Path, *, compiler: str = "cc") -> Outcome:
236
+ """Explicitly convert, compile and execute the saved fixture suite.
237
+
238
+ Evidence covers those fixtures on the selected engine/compiler/host.
239
+ It is not a proof of all inputs and is not a security attestation.
240
+ """
241
+ project = Project.load(directory)
242
+ report = {"schema": REPORT_SCHEMA, "sdk_version": SDK_VERSION, "status": "incomplete",
243
+ "project_sha256": project.sha256, "cases": []}
244
+ atomic_write(project.report_path, canonical(report))
245
+ try:
246
+ self._connection.ensure_current()
247
+ guide = self._connection.reference()
248
+ scanned = self._scan(project)
249
+ if scanned["issues"]:
250
+ raise SDKError("SDK_DOCUMENTATION_REQUIRED", "Complete the documentation and example links before verification.",
251
+ details={"issues": scanned["issues"]})
252
+ report["engine"] = dict(self._connection.snapshot.identity)
253
+ inspection = self._connection.call("inspect", {"declaration": project.document["declaration"]})
254
+ report["extension_fingerprint"] = inspection["fingerprint"]
255
+ document = project.document
256
+ kinds = {case["expect"]["kind"] for case in document["cases"]}
257
+ policy = guide.get("verification", {})
258
+ if policy.get("policy") not in ("scalar-fixtures/0.1", "scalar-fixtures/0.2"):
259
+ raise SDKError("SDK_CAPABILITY", "Unsupported engine fixture policy.")
260
+ required_kinds = set(policy["required_case_kinds"])
261
+ if not required_kinds <= {"run", "reject"}:
262
+ raise SDKError("SDK_CAPABILITY", "Engine requires an unsupported fixture kind.")
263
+ if not required_kinds <= kinds:
264
+ raise SDKError("SDK_INCOMPLETE_SUITE", "Verification requires successful native fixtures and explicit rejected-source fixtures.")
265
+ toolchain = compiler_identity(compiler, guide["native_test"], timeout=self.timeout, cancel=self.cancel)
266
+ report["compiler"] = toolchain
267
+ for i,case in enumerate(document["cases"]):
268
+ self._notify("case", name=case["name"], index=i, total=len(document["cases"]))
269
+ result = self._convert(project, case)
270
+ if result["status"] in ("InternalFailure", "Canceled"):
271
+ raise SDKError("SDK_ENGINE_RESULT", "Engine ended with " + result["status"],
272
+ status="canceled" if result["status"] == "Canceled" else "internal_failure",
273
+ details={"diagnostics": result["diagnostics"]})
274
+ check = {"name": case["name"], "file": case["file"], "expected": case["expect"],
275
+ "conversion_status": result["status"], "diagnostics": result["diagnostics"],
276
+ "generated_c_sha256": digest(result["generated_c"].encode()) if result.get("generated_c") else None}
277
+ check["operations_used"] = sorted({operation
278
+ for extension in (result.get("conversion_summary") or {}).get("extensions", [])
279
+ for operation in extension.get("operations_used", [])})
280
+ if case["expect"]["kind"] == "reject":
281
+ check["passed"] = (result["status"] == "Rejected" and result.get("generated_c") is None
282
+ and case["expect"]["code"] in {d["code"] for d in result["diagnostics"]})
283
+ elif result.get("generated_c"):
284
+ with tempfile.TemporaryDirectory(prefix="native-", dir=project.report_path.parent) as work:
285
+ check.update(execute_fixture(result["generated_c"], case["expect"], toolchain, work,
286
+ timeout=self.timeout, cancel=self.cancel))
287
+ else:
288
+ check.update(passed=False, reason="Engine did not produce C for a native fixture.")
289
+ report["cases"].append(check)
290
+ project.ensure_current()
291
+ self._connection.ensure_current()
292
+ current_compiler = compiler_identity(toolchain["executable"], guide["native_test"], timeout=self.timeout, cancel=self.cancel)
293
+ if current_compiler != toolchain:
294
+ raise SDKError("SDK_STALE_COMPILER", "Compiler changed while verifying; re-run verification.")
295
+ coverage = self._coverage(inspection, report["cases"])
296
+ report["coverage"] = coverage
297
+ doc_coverage = self._documentation_coverage(project, inspection, report["cases"])
298
+ report["documentation"] = doc_coverage
299
+ complete = (policy["policy"] != "scalar-fixtures/0.2" or not coverage["missing"]) and not doc_coverage["missing"]
300
+ report["status"] = "passed" if complete and all(c["passed"] for c in report["cases"]) else "failed"
301
+ report["scope"] = guide["native_test"]["scope"]
302
+ report["evidence_sha256"] = digest(canonical(report))
303
+ atomic_write(project.report_path, canonical(report))
304
+ diagnostics = () if complete else ({"code": "SDK_INCOMPLETE_COVERAGE",
305
+ "message": "Every export and its linked Help example must occur in a passing native fixture.",
306
+ "details": {"missing": coverage["missing"], "documentation_missing": doc_coverage["missing"]}},)
307
+ return Outcome("succeeded" if report["status"] == "passed" else "rejected",
308
+ {"report": report, "report_file": str(project.report_path)}, diagnostics)
309
+ except (SDKError, OSError) as exc:
310
+ report["status"] = "canceled" if isinstance(exc, SDKError) and exc.status == "canceled" else "incomplete"
311
+ report["problem"] = {"code": getattr(exc, "code", "SDK_IO"), "message": str(exc)}
312
+ atomic_write(project.report_path, canonical(report))
313
+ raise
314
+
315
+ def _validated_evidence(self, project, *, selected_compiler=None):
316
+ """Single evidence gate used by readiness and packaging; never run fixtures."""
317
+ if not project.report_path.is_file():
318
+ raise SDKError("SDK_VERIFICATION_REQUIRED", "Run verify successfully before building this project.")
319
+ report = parse(read(project.report_path, 8*1024*1024))
320
+ if type(report) is not dict:
321
+ raise SDKError("SDK_EVIDENCE", "Malformed verification report; run verify again.")
322
+ self._connection.ensure_current()
323
+ guide = self._connection.reference()
324
+ supplied_digest = report.get("evidence_sha256")
325
+ if (report.get("schema") != REPORT_SCHEMA or report.get("sdk_version") != SDK_VERSION
326
+ or report.get("status") != "passed" or report.get("project_sha256") != project.sha256
327
+ or report.get("engine") != self._connection.snapshot.identity
328
+ or supplied_digest != digest(canonical({k:v for k,v in report.items() if k != "evidence_sha256"}))):
329
+ raise SDKError("SDK_STALE_EVIDENCE", "No complete passing verification matches this project and engine; run verify.")
330
+ policy = guide.get("verification", {})
331
+ kinds = {case["expect"]["kind"] for case in project.document["cases"]}
332
+ if policy.get("policy") not in ("scalar-fixtures/0.1", "scalar-fixtures/0.2"):
333
+ raise SDKError("SDK_CAPABILITY", "Unsupported engine fixture policy.")
334
+ if not set(policy.get("required_case_kinds", [])) <= kinds:
335
+ raise SDKError("SDK_INCOMPLETE_SUITE", "Verification requires native run and expected rejection fixtures.")
336
+ cases = report.get("cases", [])
337
+ expected = project.document["cases"]
338
+ if type(cases) is not list or len(cases) != len(expected) or any(type(c) is not dict or c.get("passed") is not True or c.get("name") != e["name"]
339
+ or c.get("file") != e["file"] or c.get("expected") != e["expect"] for c,e in zip(cases,expected)):
340
+ raise SDKError("SDK_STALE_EVIDENCE", "Verification does not cover the complete current suite.")
341
+ compiler = report.get("compiler", {})
342
+ if type(compiler) is not dict:
343
+ raise SDKError("SDK_EVIDENCE", "Malformed compiler evidence; run verify again.")
344
+ if compiler_identity(selected_compiler or compiler.get("executable", ""), guide["native_test"], timeout=self.timeout, cancel=self.cancel) != compiler:
345
+ raise SDKError("SDK_STALE_COMPILER", "The recorded compiler or target profile changed; run verify.")
346
+ info = self._connection.call("inspect", {"declaration": project.document["declaration"]})
347
+ if info["fingerprint"] != report.get("extension_fingerprint"):
348
+ raise SDKError("SDK_STALE_EVIDENCE", "Candidate identity no longer matches the evidence.")
349
+ coverage = self._coverage(info, cases)
350
+ if guide.get("verification", {}).get("policy") == "scalar-fixtures/0.2" and (
351
+ coverage["missing"] or report.get("coverage") != coverage):
352
+ raise SDKError("SDK_INCOMPLETE_COVERAGE", "Verification must cover every exported operation; run verify.")
353
+ scanned = self._scan(project)
354
+ doc_coverage = self._documentation_coverage(project, info, cases) if not scanned["issues"] else None
355
+ if scanned["issues"] or doc_coverage["missing"] or report.get("documentation") != doc_coverage:
356
+ raise SDKError("SDK_DOCUMENTATION_REQUIRED", "Documentation and its examples must match complete current verification.",
357
+ details={"issues": scanned["issues"]})
358
+ project.ensure_current()
359
+ self._connection.ensure_current()
360
+ return report, info, scanned
361
+
362
+ @operation
363
+ def readiness(self, directory: str | Path, *, compiler: str | None = None) -> Outcome:
364
+ """Check packaging readiness without compiling or running fixtures.
365
+
366
+ Identifies the compiler with its version command when evidence exists.
367
+ Only ready-to-package is a successful approval. All clients use this
368
+ same result; Build independently repeats the same evidence gate.
369
+ """
370
+ from .readiness import evaluate
371
+ return evaluate(self, directory, compiler=compiler)
372
+
373
+ @operation
374
+ def open_project(self, directory: str | Path) -> Outcome:
375
+ """Read an immutable editor snapshot without executing project code."""
376
+ from .editing import open_project
377
+ self._notify("read", name="Read saved project")
378
+ result = open_project(directory)
379
+ self._notify("read", name="Project loaded")
380
+ return result
381
+
382
+ @operation
383
+ def save_project(self, directory: str | Path, document: dict, *, expected_sha256: str) -> Outcome:
384
+ """Validate and atomically save project.json, refusing external edits."""
385
+ from .editing import save_project
386
+ self._notify("save", name="Validate and save project")
387
+ return save_project(directory, document, expected_sha256=expected_sha256)
388
+
389
+ @operation
390
+ def validate_project(self, directory: str | Path, document: dict, *, expected_sha256: str) -> Outcome:
391
+ """Check editor data and file budgets without saving or executing it."""
392
+ from .editing import current, validate_draft
393
+ self._notify("validate", name="Check project draft")
394
+ project = current(directory, expected_sha256)
395
+ data = validate_draft(project, document, dict(project.sources))
396
+ project.ensure_current()
397
+ self._notify("validate", name="Project draft checked")
398
+ return {"document": parse(data), "project_sha256": project.sha256}
399
+
400
+ @operation
401
+ def save_source(self, directory: str | Path, filename: str, source: str, *, expected_sha256: str) -> Outcome:
402
+ """Atomically save an existing fixture; preserve files on conflict/failure."""
403
+ from .editing import save_source
404
+ self._notify("save", name="Validate and save fixture")
405
+ return save_source(directory, filename, source, expected_sha256=expected_sha256)
406
+
407
+ @operation
408
+ def build(self, directory: str | Path, destination: str | Path, *, compiler: str | None = None) -> Outcome:
409
+ """Write a package only when complete passing evidence still matches."""
410
+ project = Project.load(directory)
411
+ report, info, scanned = self._validated_evidence(project, selected_compiler=compiler)
412
+ supplied_digest = report["evidence_sha256"]
413
+ content = self._package_content(project, report)
414
+ from .package_metadata import archive_format
415
+ package_format = archive_format(content)
416
+ project.ensure_current()
417
+ destination = Path(destination).absolute()
418
+ protected = {project.root/"project.json", project.report_path, *(project.root/name for name,_ in project.sources)}
419
+ if destination.resolve() in {path.resolve() for path in protected}:
420
+ raise SDKError("SDK_ARGUMENT", "Package output cannot overwrite project inputs or evidence.")
421
+ if destination.suffix != ".pcfplugin":
422
+ raise SDKError("SDK_ARGUMENT", "Package destination must end in .pcfplugin.")
423
+ atomic_write(destination, content)
424
+ return {"package": str(destination), "sha256": digest(content), "bytes": len(content),
425
+ "evidence_sha256": supplied_digest, "registered": False,
426
+ "package_format": package_format, "documentation": "complete",
427
+ "project_sha256": project.sha256, "package_version": info["extension"]["version"]}
428
+
429
+ def _package_content(self, project, report):
430
+ """Ask the selected engine to validate its inert archive in memory."""
431
+ supplied_digest = report["evidence_sha256"]
432
+ result = self._connection.call("package", {"declaration": project.document["declaration"],
433
+ "metadata": project.document["metadata"],
434
+ "documentation": project.document["documentation"], "examples": self._examples(project),
435
+ "verification_producer": f"PyCForge SDK {SDK_VERSION}; fixture evidence {supplied_digest}"})
436
+ content = base64.b64decode(result["package_base64"], validate=True)
437
+ project.ensure_current()
438
+ return content
439
+
440
+ @staticmethod
441
+ def _coverage(inspection, cases):
442
+ required = {f["operation_id"] for f in inspection["extension"]["functions"]}
443
+ used = {operation for case in cases if case.get("passed") is True
444
+ and case["expected"]["kind"] == "run" for operation in case.get("operations_used", [])}
445
+ return {"kind": "source-call-coverage", "required": sorted(required),
446
+ "covered": sorted(required & used), "missing": sorted(required - used),
447
+ "scope": "Calls present in successfully executed fixture programs; not dynamic branch coverage or a proof of all inputs."}
448
+
449
+ @operation
450
+ def register(self, package: str | Path, *, store: str | Path | None = None) -> Outcome:
451
+ """Explicitly ask PyCForge to register a package in the selected registry."""
452
+ row = self._connection.call("register", {"file": str(Path(package).absolute()),
453
+ "store": None if store is None else str(Path(store).absolute())})
454
+ return Outcome("succeeded" if row["status"] == "Ready" else "rejected", {"registration": row})
@@ -0,0 +1,88 @@
1
+ """Validate a versioned engine-owned workbench; no library-name dispatch."""
2
+ import re
3
+ from .project import parse
4
+ from .results import SDKError
5
+
6
+ FEATURES = {"declaration-forms/1", "html-help/1", "import-catalogue/1"}
7
+ KINDS = {"text", "multiline", "choice", "json", "boolean"}
8
+ NAME = re.compile(r"[A-Za-z_][A-Za-z0-9_]{0,127}\Z")
9
+
10
+
11
+ def require(condition, message):
12
+ if not condition:
13
+ raise SDKError("SDK_WORKBENCH", message + " Keep the last compatible reference or update the SDK.")
14
+
15
+
16
+ def text(value):
17
+ return type(value) is str and 0 < len(value) <= 8192
18
+
19
+
20
+ def validate(snapshot):
21
+ """Major 1 permits additive metadata; unknown required semantics are refused."""
22
+ raw = snapshot.files.get("workbench.json")
23
+ if raw is None:
24
+ return None
25
+ data = parse(raw)
26
+ require(type(data) is dict and type(data.get("schema")) is str and
27
+ re.fullmatch(r"pycforge\.sdk-workbench/1\.[0-9]+", data["schema"]), "Unsupported workbench schema.")
28
+ features = data.get("required_features")
29
+ require(type(features) is list and all(type(x) is str for x in features) and
30
+ set(features) <= FEATURES and len(features) == len(set(features)), "Unsupported workbench requirements.")
31
+ profiles = data.get("profiles")
32
+ require(type(profiles) is list and 1 <= len(profiles) <= 256, "Invalid authoring profiles.")
33
+ schemas = set()
34
+ for profile in profiles:
35
+ require(type(profile) is dict and text(profile.get("declaration_schema")) and text(profile.get("title")), "Incomplete authoring profile.")
36
+ require(profile["declaration_schema"] not in schemas, "Duplicate authoring profile.")
37
+ require(type(profile.get("description", "")) is str and len(profile.get("description", "")) <= 8192, "Invalid profile explanation.")
38
+ schemas.add(profile["declaration_schema"])
39
+ for group in ("fields", "function_fields"):
40
+ fields = profile.get(group)
41
+ require(type(fields) is list and len(fields) <= 128, "Invalid authoring fields.")
42
+ names = set()
43
+ for field in fields:
44
+ require(type(field) is dict and type(field.get("name")) is str and NAME.fullmatch(field["name"]), "Invalid field name.")
45
+ require(field["name"] not in names and field["name"] != "schema", "Duplicate or reserved authoring field.")
46
+ names.add(field["name"])
47
+ require(text(field.get("title")) and type(field.get("description", "")) is str and
48
+ len(field.get("description", "")) <= 8192, "Missing field explanation.")
49
+ require(field.get("kind") in KINDS and type(field.get("advanced", False)) is bool, "Unsupported authoring control.")
50
+ if field["kind"] == "choice":
51
+ options = field.get("options")
52
+ require(type(options) is list and 1 <= len(options) <= 1024, "Invalid operation choices.")
53
+ values = []
54
+ for option in options:
55
+ require(type(option) is dict and text(option.get("title")) and
56
+ type(option.get("value")) in (str, int, float, bool, type(None)), "Invalid operation choice.")
57
+ identity = (type(option["value"]), option["value"])
58
+ require(identity not in values, "Duplicate operation choice.")
59
+ values.append(identity)
60
+ for key in ("description", "signature"):
61
+ require(type(option.get(key, "")) is str and len(option.get(key, "")) <= 8192, "Invalid operation explanation.")
62
+ operation = profile.get("operation_field", "")
63
+ require(type(operation) is str and (not operation or operation in {f["name"] for f in profile["function_fields"]}), "Unknown operation field.")
64
+ require(type(profile.get("contract_note", "")) is str and len(profile.get("contract_note", "")) <= 8192, "Invalid contract explanation.")
65
+ docs, ids = [], set()
66
+ guides, imports = data.get("help"), data.get("imports")
67
+ require(type(guides) is list and 1 <= len(guides) <= 128 and type(imports) is list and len(imports) <= 1024, "Invalid Help inventory.")
68
+ def document(key, title, resource):
69
+ require(text(key) and key not in ids and text(title) and type(resource) is str and
70
+ resource.endswith('.html') and resource in snapshot.files, "Help resource is missing or duplicated.")
71
+ ids.add(key)
72
+ try:
73
+ content = snapshot.files[resource].decode('utf-8')
74
+ except UnicodeError as exc:
75
+ raise SDKError("SDK_WORKBENCH", "Engine Help must be UTF-8.") from exc
76
+ docs.append({"id": key, "title": title, "html": content, "resource": resource})
77
+ for guide in guides:
78
+ require(type(guide) is dict, "Invalid guide entry.")
79
+ document(guide.get("id"), guide.get("title"), guide.get("resource"))
80
+ namespaces = set()
81
+ for item in imports:
82
+ require(type(item) is dict and all(text(item.get(key)) for key in
83
+ ("id", "namespace", "version", "profile", "description")), "Incomplete import description.")
84
+ require(item["namespace"] not in namespaces, "Duplicate bundled import namespace.")
85
+ namespaces.add(item["namespace"])
86
+ require(type(item.get("operation_count")) is int and item["operation_count"] >= 0, "Invalid import operation count.")
87
+ document("import:" + item["namespace"], "*import " + item["namespace"] + " · " + item["version"], item.get("help_resource"))
88
+ return {"definition": data, "documents": docs}