procesio-cli 0.1.1__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 (647) hide show
  1. procesio_cli/__init__.py +18 -0
  2. procesio_cli/_cli.py +71 -0
  3. procesio_cli/agents/__init__.py +0 -0
  4. procesio_cli/agents/_lib/__init__.py +0 -0
  5. procesio_cli/agents/_lib/actiondef.py +24 -0
  6. procesio_cli/agents/_lib/errors.py +40 -0
  7. procesio_cli/agents/_lib/reversibility.py +236 -0
  8. procesio_cli/agents/_lib/toolrunner.py +141 -0
  9. procesio_cli/agents/connector-builder/CONNECTOR-BUILDER-PLAYBOOK.md +62 -0
  10. procesio_cli/agents/connector-builder/CONNECTOR-BUILDER-PROCESIO-INTEROP.md +76 -0
  11. procesio_cli/agents/connector-builder/CONNECTOR-BUILDER-TROUBLESHOOTING.md +60 -0
  12. procesio_cli/agents/connector-builder/README.md +51 -0
  13. procesio_cli/agents/connector-builder/agent.yaml +61 -0
  14. procesio_cli/agents/connector-builder/context.py +19 -0
  15. procesio_cli/agents/connector-builder/handlers/__init__.py +1 -0
  16. procesio_cli/agents/connector-builder/handlers/checklist.py +71 -0
  17. procesio_cli/agents/connector-builder/handlers/guidance.py +37 -0
  18. procesio_cli/agents/connector-builder/handlers/nextstep.py +221 -0
  19. procesio_cli/agents/connector-builder/handlers/status.py +35 -0
  20. procesio_cli/agents/connector-builder/knowledge.py +47 -0
  21. procesio_cli/agents/connector-builder/main.py +93 -0
  22. procesio_cli/agents/connector-builder/tests/conftest.py +95 -0
  23. procesio_cli/agents/connector-builder/tests/test_cba_agent.py +148 -0
  24. procesio_cli/agents/orchestrator/__init__.py +0 -0
  25. procesio_cli/agents/orchestrator/bootstraplib.py +166 -0
  26. procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/00-INDEX.md +60 -0
  27. procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/01-PROCESSES.md +230 -0
  28. procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/02-FORMS.md +287 -0
  29. procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/03-INTEGRATIONS.md +384 -0
  30. procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/04-DATABASE.md +293 -0
  31. procesio_cli/agents/procesio/PROCESIO-API-RELIABILITY-DOCTRINE.md +113 -0
  32. procesio_cli/agents/procesio/PROCESIO-BEST-PRACTICES.md +316 -0
  33. procesio_cli/agents/procesio/PROCESIO-BUILD-AND-TEST-PLAYBOOK.md +217 -0
  34. procesio_cli/agents/procesio/PROCESIO-DATASTORE.md +72 -0
  35. procesio_cli/agents/procesio/PROCESIO-ENVIRONMENTS.md +62 -0
  36. procesio_cli/agents/procesio/PROCESIO-SCHEDULING.md +47 -0
  37. procesio_cli/agents/procesio/PROCESIO-VISUAL-ORGANIZATION.md +175 -0
  38. procesio_cli/agents/procesio/README.md +97 -0
  39. procesio_cli/agents/procesio/__init__.py +0 -0
  40. procesio_cli/agents/procesio/agent.yaml +73 -0
  41. procesio_cli/agents/procesio/audit.py +226 -0
  42. procesio_cli/agents/procesio/checklist.py +135 -0
  43. procesio_cli/agents/procesio/context.py +19 -0
  44. procesio_cli/agents/procesio/handlers/__init__.py +0 -0
  45. procesio_cli/agents/procesio/handlers/audit.py +39 -0
  46. procesio_cli/agents/procesio/handlers/checklist.py +34 -0
  47. procesio_cli/agents/procesio/handlers/guidance.py +36 -0
  48. procesio_cli/agents/procesio/handlers/status.py +33 -0
  49. procesio_cli/agents/procesio/handlers/verify.py +39 -0
  50. procesio_cli/agents/procesio/knowledge.py +115 -0
  51. procesio_cli/agents/procesio/main.py +89 -0
  52. procesio_cli/agents/procesio/tests/__init__.py +0 -0
  53. procesio_cli/agents/procesio/tests/conftest.py +62 -0
  54. procesio_cli/agents/procesio/tests/test_audit.py +91 -0
  55. procesio_cli/agents/procesio/tests/test_checklist.py +28 -0
  56. procesio_cli/agents/procesio/tests/test_guidance.py +78 -0
  57. procesio_cli/agents/procesio/tests/test_manifest_sync.py +48 -0
  58. procesio_cli/agents/procesio/tests/test_verify.py +134 -0
  59. procesio_cli/agents/procesio/tests/test_workspace_scope.py +97 -0
  60. procesio_cli/agents/procesio/verifylib.py +222 -0
  61. procesio_cli/dashboard/README.md +117 -0
  62. procesio_cli/dashboard/__init__.py +18 -0
  63. procesio_cli/dashboard/serve.py +98 -0
  64. procesio_cli/dashboard/server/__init__.py +1 -0
  65. procesio_cli/dashboard/server/config_schemas.py +92 -0
  66. procesio_cli/dashboard/server/google.py +103 -0
  67. procesio_cli/dashboard/server/handler.py +160 -0
  68. procesio_cli/dashboard/server/inventory.py +213 -0
  69. procesio_cli/dashboard/server/jobs.py +118 -0
  70. procesio_cli/dashboard/server/llmtest.py +181 -0
  71. procesio_cli/dashboard/server/procesio_env.py +94 -0
  72. procesio_cli/dashboard/server/routes.py +74 -0
  73. procesio_cli/dashboard/server/runner.py +150 -0
  74. procesio_cli/dashboard/server/security.py +29 -0
  75. procesio_cli/dashboard/server/setup.py +211 -0
  76. procesio_cli/dashboard/server/validate.py +152 -0
  77. procesio_cli/dashboard/tests/conftest.py +16 -0
  78. procesio_cli/dashboard/tests/test_dashboard.py +225 -0
  79. procesio_cli/dashboard/tests/test_procesio_env.py +159 -0
  80. procesio_cli/dashboard/web/actions.js +274 -0
  81. procesio_cli/dashboard/web/api.js +79 -0
  82. procesio_cli/dashboard/web/app.js +385 -0
  83. procesio_cli/dashboard/web/copilot.js +72 -0
  84. procesio_cli/dashboard/web/google.js +121 -0
  85. procesio_cli/dashboard/web/index.html +67 -0
  86. procesio_cli/dashboard/web/procesio_env.js +187 -0
  87. procesio_cli/dashboard/web/styles.css +207 -0
  88. procesio_cli/registry.py +370 -0
  89. procesio_cli/scripts/build-router.py +249 -0
  90. procesio_cli/scripts/build-tool-skill.py +202 -0
  91. procesio_cli/scripts/check-requirements.py +131 -0
  92. procesio_cli/scripts/check-skill-governance.py +174 -0
  93. procesio_cli/scripts/evaluate-skill-routing.py +217 -0
  94. procesio_cli/scripts/evaluate-skills.py +316 -0
  95. procesio_cli/scripts/get-skill.py +122 -0
  96. procesio_cli/scripts/list-skills.py +68 -0
  97. procesio_cli/scripts/list-tools.py +73 -0
  98. procesio_cli/scripts/run-agent.py +59 -0
  99. procesio_cli/scripts/run-tool.py +123 -0
  100. procesio_cli/scripts/secret_scan.py +584 -0
  101. procesio_cli/scripts/set-credential.py +126 -0
  102. procesio_cli/scripts/validate-skills.py +530 -0
  103. procesio_cli/skills/PORTFOLIO.md +134 -0
  104. procesio_cli/skills/__init__.py +6 -0
  105. procesio_cli/skills/agent-skill-engineer/SKILL.md +226 -0
  106. procesio_cli/skills/agent-skill-engineer/evals/evals.json +422 -0
  107. procesio_cli/skills/agent-skill-engineer/references/authoring-standard.md +178 -0
  108. procesio_cli/skills/agent-skill-engineer/references/decision-framework.md +107 -0
  109. procesio_cli/skills/agent-skill-engineer/references/domain-evidence-protocol.md +248 -0
  110. procesio_cli/skills/agent-skill-engineer/references/evaluation-standard.md +191 -0
  111. procesio_cli/skills/agent-skill-engineer/references/expert-lenses.md +167 -0
  112. procesio_cli/skills/agent-skill-engineer/references/field-gate-standard.md +231 -0
  113. procesio_cli/skills/agent-skill-engineer/references/optimization-protocol.md +233 -0
  114. procesio_cli/skills/agent-skill-engineer/references/optimizer-contract.md +268 -0
  115. procesio_cli/skills/agent-skill-engineer/references/portability-standard.md +99 -0
  116. procesio_cli/skills/agent-skill-engineer/references/research-basis.md +128 -0
  117. procesio_cli/skills/agent-skill-engineer/references/review-standard.md +143 -0
  118. procesio_cli/skills/agent-skill-engineer/scripts/audit_skill.py +959 -0
  119. procesio_cli/skills/agent-skill-engineer/scripts/optimize_skill.py +891 -0
  120. procesio_cli/skills/agent-skill-engineer/scripts/scaffold_skill.py +397 -0
  121. procesio_cli/skills/evals/baseline-catalog.json +14 -0
  122. procesio_cli/skills/evals/baseline-routing-v2.json +38 -0
  123. procesio_cli/skills/evals/baseline.json +37 -0
  124. procesio_cli/skills/evals/behavioral.json +367 -0
  125. procesio_cli/skills/evals/field-boundary-development-v1.json +126 -0
  126. procesio_cli/skills/evals/field-closeout-correction-development-v1.json +23 -0
  127. procesio_cli/skills/evals/field-closeout-development-v1.json +89 -0
  128. procesio_cli/skills/evals/portfolio-pressure-training-v1.json +83 -0
  129. procesio_cli/skills/evals/routing.json +363 -0
  130. procesio_cli/skills/evals/validation-baseline.json +4 -0
  131. procesio_cli/skills/procesio-cli/SKILL.md +134 -0
  132. procesio_cli/skills/procesio-cli/evals/evals.json +111 -0
  133. procesio_cli/skills/procesio-cli/evals/workflows.json +16 -0
  134. procesio_cli/skills/procesio-cli/references/connector-lifecycle.md +47 -0
  135. procesio_cli/skills/procesio-cli/references/credentials-admin.md +113 -0
  136. procesio_cli/skills/procesio-cli/references/data-verification.md +71 -0
  137. procesio_cli/skills/procesio-cli/references/documents-files.md +44 -0
  138. procesio_cli/skills/procesio-cli/references/form-e2e.md +57 -0
  139. procesio_cli/skills/procesio-cli/references/operation-contract.md +138 -0
  140. procesio_cli/skills/procesio-cli/references/process-debugging.md +65 -0
  141. procesio_cli/skills/procesio-cli/references/process-lifecycle.md +88 -0
  142. procesio_cli/skills/procesio-cli/references/schedules-webhooks.md +58 -0
  143. procesio_cli/skills/procesio-cli/references/transport-environments.md +53 -0
  144. procesio_cli/skills/procesio-cli-maintainer/SKILL.md +84 -0
  145. procesio_cli/skills/procesio-cli-maintainer/evals/evals.json +116 -0
  146. procesio_cli/skills/procesio-cli-maintainer/references/change-contract.md +34 -0
  147. procesio_cli/skills/procesio-cli-maintainer/references/mcp-compatibility.md +13 -0
  148. procesio_cli/skills/procesio-cli-maintainer/references/skill-authoring.md +51 -0
  149. procesio_cli/skills/procesio-platform-advisor/SKILL.md +82 -0
  150. procesio_cli/skills/procesio-platform-advisor/evals/evals.json +116 -0
  151. procesio_cli/skills/procesio-platform-advisor/references/capability-map.md +22 -0
  152. procesio_cli/skills/procesio-platform-advisor/references/fit-framework.md +35 -0
  153. procesio_cli/skills/procesio-platform-advisor/references/freshness-policy.md +25 -0
  154. procesio_cli/skills/procesio-platform-advisor/references/sizing-method.md +70 -0
  155. procesio_cli/skills/procesio-platform-advisor/scripts/estimate_capacity.py +99 -0
  156. procesio_cli/skills/procesio-setup/SKILL.md +180 -0
  157. procesio_cli/skills/sql-server-optimizer/SKILL.md +86 -0
  158. procesio_cli/skills/sql-server-optimizer/evals/evals.json +116 -0
  159. procesio_cli/skills/sql-server-optimizer/references/db-context.md +44 -0
  160. procesio_cli/skills/sql-server-optimizer/references/generic-mode.md +32 -0
  161. procesio_cli/skills/sql-server-optimizer/references/procesio-mode.md +40 -0
  162. procesio_cli/skills/sql-server-optimizer/references/sql-rules.md +43 -0
  163. procesio_cli/skills/sql-server-optimizer/scripts/export-indexes.sql +178 -0
  164. procesio_cli/skills/sql-server-optimizer/scripts/export-procs-and-functions.sql +118 -0
  165. procesio_cli/skills/sql-server-optimizer/scripts/export-tables.sql +367 -0
  166. procesio_cli/skills/tests/__init__.py +0 -0
  167. procesio_cli/skills/tests/test_agent_skill_engineer.py +240 -0
  168. procesio_cli/skills/tests/test_auth_failure_stop.py +25 -0
  169. procesio_cli/skills/tests/test_capacity_estimator.py +85 -0
  170. procesio_cli/skills/tests/test_field_boundary_learning.py +100 -0
  171. procesio_cli/skills/tests/test_field_closeout_learning.py +123 -0
  172. procesio_cli/skills/tests/test_field_gate_standard.py +76 -0
  173. procesio_cli/skills/tests/test_operational_playbooks.py +51 -0
  174. procesio_cli/skills/tests/test_portfolio_pressure_training.py +35 -0
  175. procesio_cli/skills/tests/test_process_lifecycle_single_run.py +25 -0
  176. procesio_cli/skills/tests/test_skill_evaluator.py +67 -0
  177. procesio_cli/skills/tests/test_skill_optimizer.py +473 -0
  178. procesio_cli/skills/tests/test_skill_portfolio_review.py +70 -0
  179. procesio_cli/skills/tests/test_skill_release_binding.py +204 -0
  180. procesio_cli/skills/tests/test_skill_routing.py +74 -0
  181. procesio_cli/skills/tests/test_skill_scaffold_v2.py +116 -0
  182. procesio_cli/skills/tests/test_validate_skills.py +115 -0
  183. procesio_cli/tools/__init__.py +0 -0
  184. procesio_cli/tools/_lib/README.md +119 -0
  185. procesio_cli/tools/_lib/__init__.py +0 -0
  186. procesio_cli/tools/_lib/accounting.py +120 -0
  187. procesio_cli/tools/_lib/contacts.py +544 -0
  188. procesio_cli/tools/_lib/creds.py +83 -0
  189. procesio_cli/tools/_lib/creds_backends.py +578 -0
  190. procesio_cli/tools/_lib/dbprofiles.py +147 -0
  191. procesio_cli/tools/_lib/dbquery.py +286 -0
  192. procesio_cli/tools/_lib/dbschema.py +225 -0
  193. procesio_cli/tools/_lib/io.py +54 -0
  194. procesio_cli/tools/_lib/manifest.py +297 -0
  195. procesio_cli/tools/_lib/skill_release.py +127 -0
  196. procesio_cli/tools/_lib/skill_resources.py +118 -0
  197. procesio_cli/tools/_lib/userdata.py +228 -0
  198. procesio_cli/tools/_lib/webserialize/__init__.py +16 -0
  199. procesio_cli/tools/_lib/webserialize/admin.py +61 -0
  200. procesio_cli/tools/_lib/webserialize/client.py +264 -0
  201. procesio_cli/tools/_lib/webserialize/config.py +96 -0
  202. procesio_cli/tools/_lib/webserialize/errors.py +27 -0
  203. procesio_cli/tools/_lib/webserialize/framing.py +45 -0
  204. procesio_cli/tools/_lib/webserialize/registry.py +47 -0
  205. procesio_cli/tools/_lib/webserialize/runtime.py +61 -0
  206. procesio_cli/tools/_lib/webserialize/server.py +510 -0
  207. procesio_cli/tools/_lib/websession.py +194 -0
  208. procesio_cli/tools/connector-builder/CONNECTOR-BUILDER-API-NOTES.md +91 -0
  209. procesio_cli/tools/connector-builder/README.md +101 -0
  210. procesio_cli/tools/connector-builder/SKILL.md +248 -0
  211. procesio_cli/tools/connector-builder/__init__.py +7 -0
  212. procesio_cli/tools/connector-builder/actiondef.py +24 -0
  213. procesio_cli/tools/connector-builder/client.py +251 -0
  214. procesio_cli/tools/connector-builder/errors.py +44 -0
  215. procesio_cli/tools/connector-builder/gen_manifest.py +142 -0
  216. procesio_cli/tools/connector-builder/handlers/__init__.py +1 -0
  217. procesio_cli/tools/connector-builder/handlers/admin.py +182 -0
  218. procesio_cli/tools/connector-builder/handlers/auth.py +74 -0
  219. procesio_cli/tools/connector-builder/handlers/builds.py +396 -0
  220. procesio_cli/tools/connector-builder/handlers/common.py +104 -0
  221. procesio_cli/tools/connector-builder/handlers/files.py +111 -0
  222. procesio_cli/tools/connector-builder/handlers/raw.py +38 -0
  223. procesio_cli/tools/connector-builder/handlers/telemetry.py +39 -0
  224. procesio_cli/tools/connector-builder/main.py +94 -0
  225. procesio_cli/tools/connector-builder/tests/conftest.py +146 -0
  226. procesio_cli/tools/connector-builder/tests/test_cb_client.py +86 -0
  227. procesio_cli/tools/connector-builder/tests/test_cb_dispatch.py +105 -0
  228. procesio_cli/tools/connector-builder/tests/test_cb_manifest_sync.py +76 -0
  229. procesio_cli/tools/connector-builder/tests/test_cb_wait.py +123 -0
  230. procesio_cli/tools/connector-builder/tool.yaml +671 -0
  231. procesio_cli/tools/framework-map/.gitattributes +2 -0
  232. procesio_cli/tools/framework-map/README.md +98 -0
  233. procesio_cli/tools/framework-map/SKILL.md +30 -0
  234. procesio_cli/tools/framework-map/app.js +188 -0
  235. procesio_cli/tools/framework-map/fm_builder.py +476 -0
  236. procesio_cli/tools/framework-map/fm_catalog.py +19 -0
  237. procesio_cli/tools/framework-map/fm_ro_catalog.py +94 -0
  238. procesio_cli/tools/framework-map/fm_strings.py +101 -0
  239. procesio_cli/tools/framework-map/main.py +95 -0
  240. procesio_cli/tools/framework-map/styles.css +214 -0
  241. procesio_cli/tools/framework-map/tests/conftest.py +33 -0
  242. procesio_cli/tools/framework-map/tests/test_fm_build.py +126 -0
  243. procesio_cli/tools/framework-map/tests/test_fm_manifest_sync.py +63 -0
  244. procesio_cli/tools/framework-map/tests/test_fm_store_tree.py +75 -0
  245. procesio_cli/tools/framework-map/tool.yaml +61 -0
  246. procesio_cli/tools/mysql/MOVED-TO-CENTRAL.md +29 -0
  247. procesio_cli/tools/mysql/README.md +196 -0
  248. procesio_cli/tools/mysql/SKILL.md +37 -0
  249. procesio_cli/tools/mysql/__init__.py +0 -0
  250. procesio_cli/tools/mysql/connection.py +191 -0
  251. procesio_cli/tools/mysql/main.py +487 -0
  252. procesio_cli/tools/mysql/profiles.template.json +1 -0
  253. procesio_cli/tools/mysql/schema.py +434 -0
  254. procesio_cli/tools/mysql/tests/__init__.py +0 -0
  255. procesio_cli/tools/mysql/tests/conftest.py +21 -0
  256. procesio_cli/tools/mysql/tests/test_manifest_sync.py +68 -0
  257. procesio_cli/tools/mysql/tests/test_mysql.py +201 -0
  258. procesio_cli/tools/mysql/tests/test_mysql_schema.py +337 -0
  259. procesio_cli/tools/mysql/tool.yaml +112 -0
  260. procesio_cli/tools/procesio/DTO-SUBTOOLS-NOTE.md +360 -0
  261. procesio_cli/tools/procesio/FORM-DEV-GUIDE/00-INDEX.md +67 -0
  262. procesio_cli/tools/procesio/FORM-DEV-GUIDE/01-ANATOMY.md +209 -0
  263. procesio_cli/tools/procesio/FORM-DEV-GUIDE/02-CODE-INJECTION.md +309 -0
  264. procesio_cli/tools/procesio/FORM-DEV-GUIDE/03-DOM-CONTRACT.md +370 -0
  265. procesio_cli/tools/procesio/FORM-DEV-GUIDE/04-INTERACTION-RECIPES.md +600 -0
  266. procesio_cli/tools/procesio/FORM-DEV-GUIDE/05-STEPPER-AND-MOTION.md +426 -0
  267. procesio_cli/tools/procesio/FORM-DEV-GUIDE/06-PROCESS-INTEGRATION.md +347 -0
  268. procesio_cli/tools/procesio/FORM-DEV-GUIDE/07-DEPLOY-WORKFLOW.md +294 -0
  269. procesio_cli/tools/procesio/FORM-DEV-GUIDE/08-PITFALLS.md +569 -0
  270. procesio_cli/tools/procesio/FORM-DEV-GUIDE/09-NAVIGATION-AND-HOSTING.md +308 -0
  271. procesio_cli/tools/procesio/PHASE4-E2E-NOTES.md +594 -0
  272. procesio_cli/tools/procesio/PROCESIO-API-CORRECTIONS.md +295 -0
  273. procesio_cli/tools/procesio/PROCESIO-API-NOTES.md +6976 -0
  274. procesio_cli/tools/procesio/PROCESIO-AUTH-NOTES.md +226 -0
  275. procesio_cli/tools/procesio/PROCESIO-CARD-BUILD-NOTES.md +183 -0
  276. procesio_cli/tools/procesio/PROCESIO-CONNECTORS-NOTES.md +141 -0
  277. procesio_cli/tools/procesio/PROCESIO-CUSTOM-ACTION-NOTES.md +179 -0
  278. procesio_cli/tools/procesio/PROCESIO-DOCS-FIX-REPORT.md +123 -0
  279. procesio_cli/tools/procesio/PROCESIO-ENVIRONMENTS-NOTES.md +94 -0
  280. procesio_cli/tools/procesio/PROCESIO-FE-VALIDATION-NOTES.md +107 -0
  281. procesio_cli/tools/procesio/PROCESIO-FOREACH-NOTES.md +199 -0
  282. procesio_cli/tools/procesio/PROCESIO-FORM-API-HANG-NOTE.md +101 -0
  283. procesio_cli/tools/procesio/PROCESIO-FORM-SUBMISSION-NOTES.md +172 -0
  284. procesio_cli/tools/procesio/PROCESIO-HTML-TO-DOCX-NOTES.md +110 -0
  285. procesio_cli/tools/procesio/PROCESIO-INSTANCE-HISTORY-NOTES.md +242 -0
  286. procesio_cli/tools/procesio/PROCESIO-METERING-NOTES.md +201 -0
  287. procesio_cli/tools/procesio/PROCESIO-NODE-CODE-NOTES.md +279 -0
  288. procesio_cli/tools/procesio/PROCESIO-NODE-MODULE-WHITELIST.md +113 -0
  289. procesio_cli/tools/procesio/PROCESIO-PYTHON-ACTION-NOTES.md +165 -0
  290. procesio_cli/tools/procesio/PROCESIO-QUERY-STORE-NOTES.md +826 -0
  291. procesio_cli/tools/procesio/PROCESIO-RECONCILIATION-PATTERNS.md +104 -0
  292. procesio_cli/tools/procesio/PROCESIO-RESOURCE-MODEL-NOTES.md +1100 -0
  293. procesio_cli/tools/procesio/PROCESIO-SEND-EMAIL-CRED-OPTIONALITY.md +45 -0
  294. procesio_cli/tools/procesio/PROCESIO-SEND-EMAIL-NOTES.md +252 -0
  295. procesio_cli/tools/procesio/PROCESIO-SQL-ACTIONS-NOTES.md +284 -0
  296. procesio_cli/tools/procesio/PROCESIO-USAGE-GUIDE.md +219 -0
  297. procesio_cli/tools/procesio/README.md +341 -0
  298. procesio_cli/tools/procesio/SCHEDULE-INPUT-SECURITY-NOTES.md +63 -0
  299. procesio_cli/tools/procesio/SKILL.md +694 -0
  300. procesio_cli/tools/procesio/__init__.py +1 -0
  301. procesio_cli/tools/procesio/actiondef.py +27 -0
  302. procesio_cli/tools/procesio/assets/html2docx/html2docx.js +2155 -0
  303. procesio_cli/tools/procesio/auth.py +354 -0
  304. procesio_cli/tools/procesio/autogen.py +121 -0
  305. procesio_cli/tools/procesio/client.py +355 -0
  306. procesio_cli/tools/procesio/config.py +96 -0
  307. procesio_cli/tools/procesio/data/endpoints.json +2901 -0
  308. procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/01-authentication.md +180 -0
  309. procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/02-conventions.md +116 -0
  310. procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/ANONYMOUS-SURFACE.md +51 -0
  311. procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/README.md +104 -0
  312. procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/SYMBOL-INDEX.md +444 -0
  313. procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/03-auth-users-workspaces.md +731 -0
  314. procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/04-processes.md +913 -0
  315. procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/05-actions.md +605 -0
  316. procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/06-files.md +237 -0
  317. procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/07-forms-documents.md +985 -0
  318. procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/08-credentials.md +532 -0
  319. procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/09-datastore-datatypes.md +830 -0
  320. procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/10-custom-urls.md +319 -0
  321. procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/11-subscriptions-resources-analytics.md +455 -0
  322. procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/12-webhooks-notifications-misc.md +519 -0
  323. procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/13-realtime-signalr.md +153 -0
  324. procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/99-internal-and-other-services.md +52 -0
  325. procesio_cli/tools/procesio/docs_info/FormBuilder mock.ts +5725 -0
  326. procesio_cli/tools/procesio/docs_info/Procesio Platform Actions.json +30219 -0
  327. procesio_cli/tools/procesio/docs_info/form-config-enums.ts +92 -0
  328. procesio_cli/tools/procesio/docs_info/form-theme.ts +1603 -0
  329. procesio_cli/tools/procesio/docs_info/process-validation-reference-1.md +2739 -0
  330. procesio_cli/tools/procesio/dto/__init__.py +13 -0
  331. procesio_cli/tools/procesio/dto/credential/builder.py +179 -0
  332. procesio_cli/tools/procesio/dto/credential/config.schema.json +19 -0
  333. procesio_cli/tools/procesio/dto/credential/description.md +193 -0
  334. procesio_cli/tools/procesio/dto/credential/fixtures/rest.config.json +11 -0
  335. procesio_cli/tools/procesio/dto/credential/fixtures/rest.dto.json +28 -0
  336. procesio_cli/tools/procesio/dto/credential/fixtures/rest.template.json +44 -0
  337. procesio_cli/tools/procesio/dto/credential/template.dto.json +16 -0
  338. procesio_cli/tools/procesio/dto/data/_refresh.py +147 -0
  339. procesio_cli/tools/procesio/dto/data/action_catalog.json +30825 -0
  340. procesio_cli/tools/procesio/dto/data/action_families.json +55 -0
  341. procesio_cli/tools/procesio/dto/data/platform_types.json +182 -0
  342. procesio_cli/tools/procesio/dto/datatype/builder.py +223 -0
  343. procesio_cli/tools/procesio/dto/datatype/config.schema.json +47 -0
  344. procesio_cli/tools/procesio/dto/datatype/description.md +85 -0
  345. procesio_cli/tools/procesio/dto/datatype/fixtures/customer.config.json +41 -0
  346. procesio_cli/tools/procesio/dto/datatype/fixtures/customer.dto.json +164 -0
  347. procesio_cli/tools/procesio/dto/datatype/template.dto.json +37 -0
  348. procesio_cli/tools/procesio/dto/document/builder.py +193 -0
  349. procesio_cli/tools/procesio/dto/document/config.schema.json +33 -0
  350. procesio_cli/tools/procesio/dto/document/description.md +124 -0
  351. procesio_cli/tools/procesio/dto/document/fixtures/invoice.config.json +16 -0
  352. procesio_cli/tools/procesio/dto/document/fixtures/invoice.dto.json +32 -0
  353. procesio_cli/tools/procesio/dto/document/template.dto.json +14 -0
  354. procesio_cli/tools/procesio/dto/form/FORM-STYLING-NOTES.md +142 -0
  355. procesio_cli/tools/procesio/dto/form/GOLDEN-DRIFT-NOTES.md +72 -0
  356. procesio_cli/tools/procesio/dto/form/RUN-PROCESS-RESULT-NOTES.md +80 -0
  357. procesio_cli/tools/procesio/dto/form/addelement.py +277 -0
  358. procesio_cli/tools/procesio/dto/form/builder.py +1009 -0
  359. procesio_cli/tools/procesio/dto/form/capture_goldens.py +106 -0
  360. procesio_cli/tools/procesio/dto/form/code_cipher.py +67 -0
  361. procesio_cli/tools/procesio/dto/form/config.schema.json +76 -0
  362. procesio_cli/tools/procesio/dto/form/data_shell.json +1 -0
  363. procesio_cli/tools/procesio/dto/form/description.md +346 -0
  364. procesio_cli/tools/procesio/dto/form/elements/approval.json +259 -0
  365. procesio_cli/tools/procesio/dto/form/elements/assignee.json +137 -0
  366. procesio_cli/tools/procesio/dto/form/elements/button.json +125 -0
  367. procesio_cli/tools/procesio/dto/form/elements/chart.json +341 -0
  368. procesio_cli/tools/procesio/dto/form/elements/chat.json +199 -0
  369. procesio_cli/tools/procesio/dto/form/elements/checkbox.json +153 -0
  370. procesio_cli/tools/procesio/dto/form/elements/column.json +77 -0
  371. procesio_cli/tools/procesio/dto/form/elements/columns.json +78 -0
  372. procesio_cli/tools/procesio/dto/form/elements/datetime-input.json +304 -0
  373. procesio_cli/tools/procesio/dto/form/elements/divider.json +54 -0
  374. procesio_cli/tools/procesio/dto/form/elements/dropdown.json +130 -0
  375. procesio_cli/tools/procesio/dto/form/elements/dynamic-table-row.json +253 -0
  376. procesio_cli/tools/procesio/dto/form/elements/file-upload.json +196 -0
  377. procesio_cli/tools/procesio/dto/form/elements/file-viewer.json +169 -0
  378. procesio_cli/tools/procesio/dto/form/elements/heading.json +79 -0
  379. procesio_cli/tools/procesio/dto/form/elements/icon.json +107 -0
  380. procesio_cli/tools/procesio/dto/form/elements/image.json +174 -0
  381. procesio_cli/tools/procesio/dto/form/elements/input.json +206 -0
  382. procesio_cli/tools/procesio/dto/form/elements/list.json +202 -0
  383. procesio_cli/tools/procesio/dto/form/elements/number-input.json +202 -0
  384. procesio_cli/tools/procesio/dto/form/elements/paragraph.json +79 -0
  385. procesio_cli/tools/procesio/dto/form/elements/radiobox.json +174 -0
  386. procesio_cli/tools/procesio/dto/form/elements/section.json +114 -0
  387. procesio_cli/tools/procesio/dto/form/elements/select.json +217 -0
  388. procesio_cli/tools/procesio/dto/form/elements/side-panel.json +146 -0
  389. procesio_cli/tools/procesio/dto/form/elements/signature-pad.json +141 -0
  390. procesio_cli/tools/procesio/dto/form/elements/static-table-row.json +84 -0
  391. procesio_cli/tools/procesio/dto/form/elements/step.json +105 -0
  392. procesio_cli/tools/procesio/dto/form/elements/stepper.json +126 -0
  393. procesio_cli/tools/procesio/dto/form/elements/tab.json +77 -0
  394. procesio_cli/tools/procesio/dto/form/elements/table.json +279 -0
  395. procesio_cli/tools/procesio/dto/form/elements/tabs.json +114 -0
  396. procesio_cli/tools/procesio/dto/form/elements/textarea.json +213 -0
  397. procesio_cli/tools/procesio/dto/form/enum_map.json +68 -0
  398. procesio_cli/tools/procesio/dto/form/fieldpath.py +284 -0
  399. procesio_cli/tools/procesio/dto/form/fixtures/reg.config.json +32 -0
  400. procesio_cli/tools/procesio/dto/form/fixtures/reg.elements.json +638 -0
  401. procesio_cli/tools/procesio/dto/form/sync_from_mock.py +386 -0
  402. procesio_cli/tools/procesio/dto/framework.py +125 -0
  403. procesio_cli/tools/procesio/dto/process/builder.py +1991 -0
  404. procesio_cli/tools/procesio/dto/process/config.schema.json +159 -0
  405. procesio_cli/tools/procesio/dto/process/description.md +218 -0
  406. procesio_cli/tools/procesio/dto/process/fixtures/greet.config.json +32 -0
  407. procesio_cli/tools/procesio/dto/process/fixtures/greet.dto.json +317 -0
  408. procesio_cli/tools/procesio/dto/process/naming.py +305 -0
  409. procesio_cli/tools/procesio/dto/process/normalize.py +74 -0
  410. procesio_cli/tools/procesio/dto/process/template.dto.json +32 -0
  411. procesio_cli/tools/procesio/dto/refdata.py +87 -0
  412. procesio_cli/tools/procesio/dto/registry.py +27 -0
  413. procesio_cli/tools/procesio/dto/webhook/builder.py +142 -0
  414. procesio_cli/tools/procesio/dto/webhook/config.schema.json +25 -0
  415. procesio_cli/tools/procesio/dto/webhook/description.md +92 -0
  416. procesio_cli/tools/procesio/dto/webhook/fixtures/order.config.json +10 -0
  417. procesio_cli/tools/procesio/dto/webhook/fixtures/order.dto.json +25 -0
  418. procesio_cli/tools/procesio/dto/webhook/template.dto.json +14 -0
  419. procesio_cli/tools/procesio/environments.py +264 -0
  420. procesio_cli/tools/procesio/errors.py +166 -0
  421. procesio_cli/tools/procesio/flowmodel/README.md +37 -0
  422. procesio_cli/tools/procesio/flowmodel/__init__.py +14 -0
  423. procesio_cli/tools/procesio/flowmodel/digest.py +223 -0
  424. procesio_cli/tools/procesio/flowmodel/families.py +34 -0
  425. procesio_cli/tools/procesio/flowmodel/fevalidation.py +1098 -0
  426. procesio_cli/tools/procesio/flowmodel/formdigest.py +232 -0
  427. procesio_cli/tools/procesio/flowmodel/inspect.py +78 -0
  428. procesio_cli/tools/procesio/flowmodel/model.py +82 -0
  429. procesio_cli/tools/procesio/flowmodel/nodeparam.py +871 -0
  430. procesio_cli/tools/procesio/flowmodel/reader.py +191 -0
  431. procesio_cli/tools/procesio/flowmodel/sqlparam.py +410 -0
  432. procesio_cli/tools/procesio/form_code_keys.py +50 -0
  433. procesio_cli/tools/procesio/formlint.py +292 -0
  434. procesio_cli/tools/procesio/gen_manifest.py +118 -0
  435. procesio_cli/tools/procesio/handlers/__init__.py +1 -0
  436. procesio_cli/tools/procesio/handlers/auth_actions.py +103 -0
  437. procesio_cli/tools/procesio/handlers/catalog.py +147 -0
  438. procesio_cli/tools/procesio/handlers/common.py +90 -0
  439. procesio_cli/tools/procesio/handlers/customaction_ops.py +146 -0
  440. procesio_cli/tools/procesio/handlers/datastore_ops.py +482 -0
  441. procesio_cli/tools/procesio/handlers/datatype_ops.py +275 -0
  442. procesio_cli/tools/procesio/handlers/dto_actions.py +258 -0
  443. procesio_cli/tools/procesio/handlers/environment_admin.py +146 -0
  444. procesio_cli/tools/procesio/handlers/fevalidate.py +236 -0
  445. procesio_cli/tools/procesio/handlers/files.py +141 -0
  446. procesio_cli/tools/procesio/handlers/flowgraph.py +229 -0
  447. procesio_cli/tools/procesio/handlers/flowlint.py +269 -0
  448. procesio_cli/tools/procesio/handlers/form_chains.py +336 -0
  449. procesio_cli/tools/procesio/handlers/form_code.py +277 -0
  450. procesio_cli/tools/procesio/handlers/form_element.py +199 -0
  451. procesio_cli/tools/procesio/handlers/form_events.py +441 -0
  452. procesio_cli/tools/procesio/handlers/form_update.py +270 -0
  453. procesio_cli/tools/procesio/handlers/formprocess.py +211 -0
  454. procesio_cli/tools/procesio/handlers/generic.py +135 -0
  455. procesio_cli/tools/procesio/handlers/layout.py +137 -0
  456. procesio_cli/tools/procesio/handlers/nodeparams.py +1018 -0
  457. procesio_cli/tools/procesio/handlers/process_layout.py +189 -0
  458. procesio_cli/tools/procesio/handlers/process_naming.py +213 -0
  459. procesio_cli/tools/procesio/handlers/processes.py +416 -0
  460. procesio_cli/tools/procesio/handlers/profile_admin.py +184 -0
  461. procesio_cli/tools/procesio/handlers/resource_ops.py +447 -0
  462. procesio_cli/tools/procesio/handlers/schedules.py +320 -0
  463. procesio_cli/tools/procesio/handlers/sqlactions.py +232 -0
  464. procesio_cli/tools/procesio/handlers/transport.py +463 -0
  465. procesio_cli/tools/procesio/handlers/usageguide.py +222 -0
  466. procesio_cli/tools/procesio/layout/README.md +196 -0
  467. procesio_cli/tools/procesio/layout/__init__.py +11 -0
  468. procesio_cli/tools/procesio/layout/adapter.py +736 -0
  469. procesio_cli/tools/procesio/layout/cycles.py +186 -0
  470. procesio_cli/tools/procesio/layout/dispatch.py +39 -0
  471. procesio_cli/tools/procesio/layout/elk/elk_runner.mjs +50 -0
  472. procesio_cli/tools/procesio/layout/elk/package-lock.json +21 -0
  473. procesio_cli/tools/procesio/layout/elk/package.json +11 -0
  474. procesio_cli/tools/procesio/layout/elk_engine.py +568 -0
  475. procesio_cli/tools/procesio/layout/engine.py +1311 -0
  476. procesio_cli/tools/procesio/layout/report.py +187 -0
  477. procesio_cli/tools/procesio/main.py +179 -0
  478. procesio_cli/tools/procesio/profiles.py +193 -0
  479. procesio_cli/tools/procesio/reliability.py +193 -0
  480. procesio_cli/tools/procesio/sqlformat.py +167 -0
  481. procesio_cli/tools/procesio/swagger.py +51 -0
  482. procesio_cli/tools/procesio/tests/__init__.py +0 -0
  483. procesio_cli/tools/procesio/tests/conftest.py +129 -0
  484. procesio_cli/tools/procesio/tests/test_auth.py +200 -0
  485. procesio_cli/tools/procesio/tests/test_autogen.py +78 -0
  486. procesio_cli/tools/procesio/tests/test_builder_attrpath_sqlbind.py +180 -0
  487. procesio_cli/tools/procesio/tests/test_builder_custom_action_catalog.py +72 -0
  488. procesio_cli/tools/procesio/tests/test_client.py +114 -0
  489. procesio_cli/tools/procesio/tests/test_client_reliability.py +139 -0
  490. procesio_cli/tools/procesio/tests/test_customaction.py +103 -0
  491. procesio_cli/tools/procesio/tests/test_customaction_test.py +80 -0
  492. procesio_cli/tools/procesio/tests/test_cycles.py +69 -0
  493. procesio_cli/tools/procesio/tests/test_datastore.py +378 -0
  494. procesio_cli/tools/procesio/tests/test_datastore_node.py +94 -0
  495. procesio_cli/tools/procesio/tests/test_dispatch.py +170 -0
  496. procesio_cli/tools/procesio/tests/test_document_page_size.py +19 -0
  497. procesio_cli/tools/procesio/tests/test_dto.py +734 -0
  498. procesio_cli/tools/procesio/tests/test_edit_dryrun_preview.py +96 -0
  499. procesio_cli/tools/procesio/tests/test_elk_layout.py +221 -0
  500. procesio_cli/tools/procesio/tests/test_environments.py +214 -0
  501. procesio_cli/tools/procesio/tests/test_fevalidate_gate.py +104 -0
  502. procesio_cli/tools/procesio/tests/test_fevalidation.py +317 -0
  503. procesio_cli/tools/procesio/tests/test_fieldpath_variables.py +87 -0
  504. procesio_cli/tools/procesio/tests/test_files.py +72 -0
  505. procesio_cli/tools/procesio/tests/test_flow_digest.py +202 -0
  506. procesio_cli/tools/procesio/tests/test_flowlint.py +114 -0
  507. procesio_cli/tools/procesio/tests/test_flowmodel.py +158 -0
  508. procesio_cli/tools/procesio/tests/test_form_add_element.py +256 -0
  509. procesio_cli/tools/procesio/tests/test_form_approval_gaps.py +319 -0
  510. procesio_cli/tools/procesio/tests/test_form_auto_names.py +60 -0
  511. procesio_cli/tools/procesio/tests/test_form_chains.py +217 -0
  512. procesio_cli/tools/procesio/tests/test_form_code_actions.py +188 -0
  513. procesio_cli/tools/procesio/tests/test_form_code_keys.py +92 -0
  514. procesio_cli/tools/procesio/tests/test_form_code_style.py +178 -0
  515. procesio_cli/tools/procesio/tests/test_form_delete_element.py +99 -0
  516. procesio_cli/tools/procesio/tests/test_form_element_config.py +141 -0
  517. procesio_cli/tools/procesio/tests/test_form_event_maps.py +135 -0
  518. procesio_cli/tools/procesio/tests/test_form_event_ops.py +376 -0
  519. procesio_cli/tools/procesio/tests/test_form_event_replace.py +86 -0
  520. procesio_cli/tools/procesio/tests/test_form_events.py +92 -0
  521. procesio_cli/tools/procesio/tests/test_form_parity.py +171 -0
  522. procesio_cli/tools/procesio/tests/test_form_select_source.py +74 -0
  523. procesio_cli/tools/procesio/tests/test_form_sync.py +35 -0
  524. procesio_cli/tools/procesio/tests/test_form_update.py +133 -0
  525. procesio_cli/tools/procesio/tests/test_formlint.py +155 -0
  526. procesio_cli/tools/procesio/tests/test_formlint_css_scope.py +38 -0
  527. procesio_cli/tools/procesio/tests/test_formlint_field_names.py +83 -0
  528. procesio_cli/tools/procesio/tests/test_guards.py +110 -0
  529. procesio_cli/tools/procesio/tests/test_hidden_setting_types.py +39 -0
  530. procesio_cli/tools/procesio/tests/test_html2docx_asset.py +132 -0
  531. procesio_cli/tools/procesio/tests/test_key_handle_terminology.py +45 -0
  532. procesio_cli/tools/procesio/tests/test_layout.py +574 -0
  533. procesio_cli/tools/procesio/tests/test_layout_report.py +88 -0
  534. procesio_cli/tools/procesio/tests/test_manifest_sync.py +68 -0
  535. procesio_cli/tools/procesio/tests/test_nodedelete.py +151 -0
  536. procesio_cli/tools/procesio/tests/test_nodeparam.py +826 -0
  537. procesio_cli/tools/procesio/tests/test_normalize.py +70 -0
  538. procesio_cli/tools/procesio/tests/test_payload_docs.py +86 -0
  539. procesio_cli/tools/procesio/tests/test_process_action_naming.py +170 -0
  540. procesio_cli/tools/procesio/tests/test_process_call_api_seed.py +46 -0
  541. procesio_cli/tools/procesio/tests/test_process_ext.py +373 -0
  542. procesio_cli/tools/procesio/tests/test_process_invariants.py +183 -0
  543. procesio_cli/tools/procesio/tests/test_process_layout.py +117 -0
  544. procesio_cli/tools/procesio/tests/test_process_naming.py +188 -0
  545. procesio_cli/tools/procesio/tests/test_process_query_store.py +172 -0
  546. procesio_cli/tools/procesio/tests/test_processinfo_variable.py +56 -0
  547. procesio_cli/tools/procesio/tests/test_profiles.py +127 -0
  548. procesio_cli/tools/procesio/tests/test_put_projects.py +41 -0
  549. procesio_cli/tools/procesio/tests/test_reliability.py +107 -0
  550. procesio_cli/tools/procesio/tests/test_removal_gate.py +95 -0
  551. procesio_cli/tools/procesio/tests/test_resource_ops.py +173 -0
  552. procesio_cli/tools/procesio/tests/test_save_validity.py +207 -0
  553. procesio_cli/tools/procesio/tests/test_schedule_cron_shape.py +111 -0
  554. procesio_cli/tools/procesio/tests/test_schedules.py +309 -0
  555. procesio_cli/tools/procesio/tests/test_sqlconvert.py +234 -0
  556. procesio_cli/tools/procesio/tests/test_sqlformat.py +83 -0
  557. procesio_cli/tools/procesio/tests/test_sqlparam.py +187 -0
  558. procesio_cli/tools/procesio/tests/test_superseded_actions.py +54 -0
  559. procesio_cli/tools/procesio/tests/test_surgical_concurrency.py +156 -0
  560. procesio_cli/tools/procesio/tests/test_tier4.py +123 -0
  561. procesio_cli/tools/procesio/tests/test_transport.py +147 -0
  562. procesio_cli/tools/procesio/tests/test_transport_data_stores.py +168 -0
  563. procesio_cli/tools/procesio/tests/test_transport_mapper_repair.py +150 -0
  564. procesio_cli/tools/procesio/tests/test_transport_webhook_strip.py +253 -0
  565. procesio_cli/tools/procesio/tests/test_usage_guide.py +96 -0
  566. procesio_cli/tools/procesio/tool.yaml +12486 -0
  567. procesio_cli/tools/sqlserver/MOVED-TO-CENTRAL.md +29 -0
  568. procesio_cli/tools/sqlserver/README.md +192 -0
  569. procesio_cli/tools/sqlserver/SKILL.md +37 -0
  570. procesio_cli/tools/sqlserver/SQLSERVER-SCHEMA-NOTES.md +284 -0
  571. procesio_cli/tools/sqlserver/__init__.py +0 -0
  572. procesio_cli/tools/sqlserver/connection.py +242 -0
  573. procesio_cli/tools/sqlserver/main.py +521 -0
  574. procesio_cli/tools/sqlserver/profiles.template.json +1 -0
  575. procesio_cli/tools/sqlserver/schema.py +600 -0
  576. procesio_cli/tools/sqlserver/tests/__init__.py +0 -0
  577. procesio_cli/tools/sqlserver/tests/conftest.py +21 -0
  578. procesio_cli/tools/sqlserver/tests/test_connection.py +75 -0
  579. procesio_cli/tools/sqlserver/tests/test_dbprofiles.py +92 -0
  580. procesio_cli/tools/sqlserver/tests/test_dbquery.py +220 -0
  581. procesio_cli/tools/sqlserver/tests/test_manifest_sync.py +68 -0
  582. procesio_cli/tools/sqlserver/tests/test_sqlserver.py +326 -0
  583. procesio_cli/tools/sqlserver/tests/test_sqlserver_schema.py +488 -0
  584. procesio_cli/tools/sqlserver/tool.yaml +123 -0
  585. procesio_cli/tools/web/README.md +381 -0
  586. procesio_cli/tools/web/SKILL.md +37 -0
  587. procesio_cli/tools/web/WEB-AUTOMATION-NOTES.md +277 -0
  588. procesio_cli/tools/web/__init__.py +21 -0
  589. procesio_cli/tools/web/actiondef.py +24 -0
  590. procesio_cli/tools/web/api.py +444 -0
  591. procesio_cli/tools/web/brokered.py +107 -0
  592. procesio_cli/tools/web/driver.py +839 -0
  593. procesio_cli/tools/web/drivercontract.py +44 -0
  594. procesio_cli/tools/web/errors.py +54 -0
  595. procesio_cli/tools/web/handlers/__init__.py +1 -0
  596. procesio_cli/tools/web/handlers/archive.py +367 -0
  597. procesio_cli/tools/web/handlers/browse.py +182 -0
  598. procesio_cli/tools/web/handlers/contacts.py +74 -0
  599. procesio_cli/tools/web/handlers/sessmgmt.py +120 -0
  600. procesio_cli/tools/web/main.py +128 -0
  601. procesio_cli/tools/web/sessions.py +253 -0
  602. procesio_cli/tools/web/steps.py +162 -0
  603. procesio_cli/tools/web/tests/__init__.py +0 -0
  604. procesio_cli/tools/web/tests/conftest.py +197 -0
  605. procesio_cli/tools/web/tests/test_api.py +330 -0
  606. procesio_cli/tools/web/tests/test_archive.py +190 -0
  607. procesio_cli/tools/web/tests/test_brokered.py +138 -0
  608. procesio_cli/tools/web/tests/test_dispatch.py +132 -0
  609. procesio_cli/tools/web/tests/test_errors.py +60 -0
  610. procesio_cli/tools/web/tests/test_manifest_sync.py +76 -0
  611. procesio_cli/tools/web/tests/test_page_contacts.py +68 -0
  612. procesio_cli/tools/web/tests/test_sessions.py +145 -0
  613. procesio_cli/tools/web/tests/test_steps.py +210 -0
  614. procesio_cli/tools/web/tool.yaml +184 -0
  615. procesio_cli/tools/xlsx/README.md +34 -0
  616. procesio_cli/tools/xlsx/SKILL.md +28 -0
  617. procesio_cli/tools/xlsx/__init__.py +0 -0
  618. procesio_cli/tools/xlsx/main.py +129 -0
  619. procesio_cli/tools/xlsx/reader.py +91 -0
  620. procesio_cli/tools/xlsx/tests/__init__.py +0 -0
  621. procesio_cli/tools/xlsx/tests/conftest.py +39 -0
  622. procesio_cli/tools/xlsx/tests/test_xlsx.py +103 -0
  623. procesio_cli/tools/xlsx/tool.yaml +30 -0
  624. procesio_cli/webplatform/aat_mcp/AAT-MCP-NOTES.md +244 -0
  625. procesio_cli/webplatform/aat_mcp/README.md +78 -0
  626. procesio_cli/webplatform/aat_mcp/bridge.py +705 -0
  627. procesio_cli/webplatform/aat_mcp/chat_server.py +194 -0
  628. procesio_cli/webplatform/aat_mcp/chat_surface.snapshot.json +668 -0
  629. procesio_cli/webplatform/aat_mcp/chat_surface.yaml +372 -0
  630. procesio_cli/webplatform/aat_mcp/gate.py +68 -0
  631. procesio_cli/webplatform/aat_mcp/http_server.py +139 -0
  632. procesio_cli/webplatform/aat_mcp/protocol.py +175 -0
  633. procesio_cli/webplatform/aat_mcp/server.py +306 -0
  634. procesio_cli/webplatform/aat_mcp/tests/conftest.py +8 -0
  635. procesio_cli/webplatform/aat_mcp/tests/test_aat_mcp.py +255 -0
  636. procesio_cli/webplatform/aat_mcp/tests/test_chat_surface.py +247 -0
  637. procesio_cli/webplatform/aat_mcp/tests/test_discovery.py +489 -0
  638. procesio_cli/webplatform/aat_mcp/tests/test_multiuser.py +86 -0
  639. procesio_cli/webplatform/aat_mcp/tests/test_progressive_discovery.py +89 -0
  640. procesio_cli/webplatform/aat_mcp/tests/test_protocol.py +180 -0
  641. procesio_cli/webplatform/aat_mcp/tests/test_skill_discovery.py +23 -0
  642. procesio_cli-0.1.1.dist-info/METADATA +467 -0
  643. procesio_cli-0.1.1.dist-info/RECORD +647 -0
  644. procesio_cli-0.1.1.dist-info/WHEEL +4 -0
  645. procesio_cli-0.1.1.dist-info/entry_points.txt +7 -0
  646. procesio_cli-0.1.1.dist-info/licenses/LICENSE +201 -0
  647. procesio_cli-0.1.1.dist-info/licenses/NOTICE +5 -0
@@ -0,0 +1,574 @@
1
+ """Tests for the deterministic canvas layout engine + .procesio adapter."""
2
+ from __future__ import annotations
3
+
4
+ import copy
5
+ import glob
6
+ import json
7
+ import os
8
+
9
+ import pytest
10
+
11
+ from tools.procesio.layout import adapter, engine
12
+
13
+ EXPORTS = os.path.join(os.path.dirname(__file__), "..", "docs_info", "Exports")
14
+
15
+
16
+ def _diamond():
17
+ """start -> a -> {b,c} -> d -> stop, plus an error edge a->err."""
18
+ nodes = [{"id": i} for i in ("start", "a", "b", "c", "d", "err", "stop")]
19
+ edges = [
20
+ {"source": "start", "dest": "a"}, {"source": "a", "dest": "b"},
21
+ {"source": "a", "dest": "c"}, {"source": "b", "dest": "d"},
22
+ {"source": "c", "dest": "d"}, {"source": "d", "dest": "stop"},
23
+ {"source": "a", "dest": "err", "type": 1},
24
+ ]
25
+ return nodes, edges
26
+
27
+
28
+ def _rects(res):
29
+ """node id -> (x0, y0, x1, y1) using default 48x48."""
30
+ out = {}
31
+ for nid, p in res["positions"].items():
32
+ out[nid] = (p["x"] - 24, p["y"] - 24, p["x"] + 24, p["y"] + 24)
33
+ return out
34
+
35
+
36
+ def test_engine_deterministic():
37
+ n, e = _diamond()
38
+ assert engine.layout(n, e) == engine.layout(copy.deepcopy(n), copy.deepcopy(e))
39
+
40
+
41
+ def test_engine_left_to_right_by_depth():
42
+ n, e = _diamond()
43
+ p = engine.layout(n, e)["positions"]
44
+ # start is leftmost; each node sits right of its predecessor on the happy path
45
+ assert p["start"]["x"] == min(q["x"] for q in p.values())
46
+ assert p["a"]["x"] > p["start"]["x"] > -1
47
+ assert p["d"]["x"] > p["b"]["x"] and p["d"]["x"] > p["c"]["x"]
48
+ assert p["stop"]["x"] > p["d"]["x"]
49
+
50
+
51
+ def test_engine_no_overlap():
52
+ n, e = _diamond()
53
+ rects = _rects(engine.layout(n, e))
54
+ ids = list(rects)
55
+ for i in range(len(ids)):
56
+ for j in range(i + 1, len(ids)):
57
+ ax0, ay0, ax1, ay1 = rects[ids[i]]
58
+ bx0, by0, bx1, by1 = rects[ids[j]]
59
+ overlap = ax0 < bx1 and bx0 < ax1 and ay0 < by1 and by0 < ay1
60
+ assert not overlap, f"{ids[i]} overlaps {ids[j]}"
61
+
62
+
63
+ def test_engine_error_target_drops_below():
64
+ n, e = _diamond()
65
+ p = engine.layout(n, e)["positions"]
66
+ # the error handler sits below the whole main band
67
+ main_max_y = max(p[k]["y"] for k in ("start", "a", "b", "c", "d", "stop"))
68
+ assert p["err"]["y"] > main_max_y
69
+
70
+
71
+ def test_engine_container_contains_children():
72
+ nodes = [{"id": "start"}, {"id": "loop", "kind": "area"},
73
+ {"id": "k1", "parent_id": "loop"}, {"id": "k2", "parent_id": "loop"},
74
+ {"id": "stop"}]
75
+ edges = [{"source": "start", "dest": "loop"}, {"source": "loop", "dest": "k1"},
76
+ {"source": "k1", "dest": "k2"}, {"source": "loop", "dest": "stop"}]
77
+ res = engine.layout(nodes, edges)
78
+ frame = res["areas"]["loop"]
79
+ for kid in ("k1", "k2"):
80
+ p = res["positions"][kid]
81
+ assert frame["x"] <= p["x"] <= frame["x"] + frame["width"]
82
+ assert frame["y"] <= p["y"] <= frame["y"] + frame["height"]
83
+
84
+
85
+ # -- adapter: round-trip integrity on real exports ---------------------------
86
+
87
+ def _first_multiaction_flow(bundle):
88
+ for f in bundle.get("Flows") or []:
89
+ if len(f.get("Actions") or []) >= 3:
90
+ return f["Id"]
91
+ return None
92
+
93
+
94
+ @pytest.mark.parametrize("path", sorted(glob.glob(os.path.join(EXPORTS, "*.procesio")))[:3])
95
+ def test_adapter_changes_only_geometry(path):
96
+ bundle = json.load(open(path, encoding="utf-8"))
97
+ fid = _first_multiaction_flow(bundle)
98
+ if not fid:
99
+ pytest.skip("no multi-action flow")
100
+ before = copy.deepcopy(bundle)
101
+ res = adapter.layout_flow(bundle, flow_id=fid)
102
+ out = res["bundle"]
103
+ # input bundle is untouched (pure)
104
+ assert bundle == before
105
+ bflow = next(f for f in before["Flows"] if f["Id"] == fid)
106
+ aflow = next(f for f in out["Flows"] if f["Id"] == fid)
107
+ # topology unchanged: same action ids, ports, parameters
108
+ b_by = {a["Id"]: a for a in bflow["Actions"]}
109
+ a_by = {a["Id"]: a for a in aflow["Actions"]}
110
+ assert set(b_by) == set(a_by)
111
+ for aid in b_by:
112
+ ba, aa = b_by[aid], a_by[aid]
113
+ assert ba["Ports"] == aa["Ports"]
114
+ assert ba.get("Parameters") == aa.get("Parameters")
115
+ assert ba.get("ParentId") == aa.get("ParentId")
116
+ # everything in CustomData except position/areaSize is identical
117
+ bcd = {k: v for k, v in ba["CustomData"].items() if k not in ("position", "areaSize")}
118
+ acd = {k: v for k, v in aa["CustomData"].items() if k not in ("position", "areaSize")}
119
+ assert bcd == acd
120
+ # CanvasData (the designer viewport) is NEVER touched
121
+ assert aflow.get("CanvasData") == bflow.get("CanvasData")
122
+
123
+
124
+ @pytest.mark.parametrize("path", sorted(glob.glob(os.path.join(EXPORTS, "*.procesio")))[:3])
125
+ def test_adapter_idempotent(path):
126
+ bundle = json.load(open(path, encoding="utf-8"))
127
+ fid = _first_multiaction_flow(bundle)
128
+ if not fid:
129
+ pytest.skip("no multi-action flow")
130
+ once = adapter.layout_flow(bundle, flow_id=fid)
131
+ twice = adapter.layout_flow(once["bundle"], flow_id=fid)
132
+ assert once["positions"] == twice["positions"]
133
+
134
+
135
+ def test_linear_chain_is_one_straight_row():
136
+ n = 8
137
+ nodes = [{"id": f"n{i}"} for i in range(n)]
138
+ edges = [{"source": f"n{i}", "dest": f"n{i + 1}"} for i in range(n - 1)]
139
+ p = engine.layout(nodes, edges)["positions"]
140
+ assert len({round(v["y"]) for v in p.values()}) == 1 # all on one row
141
+ assert sorted(v["x"] for v in p.values()) == [80 + 160 * i for i in range(n)]
142
+
143
+
144
+ def test_parallel_chains_become_straight_distinct_lanes():
145
+ # the image-6 case: 3 independent P->C->S chains -> 3 straight, non-crossing lanes
146
+ nodes, edges = [], []
147
+ for k in (1, 2, 3):
148
+ for s in ("P", "C", "S"):
149
+ nodes.append({"id": f"{s}{k}"})
150
+ edges += [{"source": f"P{k}", "dest": f"C{k}"}, {"source": f"C{k}", "dest": f"S{k}"}]
151
+ p = engine.layout(nodes, edges)["positions"]
152
+ for k in (1, 2, 3): # each chain straight
153
+ assert p[f"P{k}"]["y"] == p[f"C{k}"]["y"] == p[f"S{k}"]["y"]
154
+ assert len({p[f"P{k}"]["y"] for k in (1, 2, 3)}) == 3 # 3 distinct lanes
155
+ # no crossings: the lane order is identical in every column
156
+ lane_order = lambda col: [k for _, k in sorted((p[f"{col}{k}"]["y"], k) for k in (1, 2, 3))]
157
+ assert lane_order("P") == lane_order("C") == lane_order("S")
158
+
159
+
160
+ def test_short_deadend_branch_folds_vertical():
161
+ # dec -> x -> stop1 is a short dead-end (2 nodes) -> folds vertical at dec's column;
162
+ # dec -> cont -> join is a rejoining branch (join has 2 inputs) -> stays horizontal.
163
+ nodes = [{"id": i} for i in ("start", "dec", "x", "stop1", "cont", "join", "extra", "stop2")]
164
+ edges = [
165
+ {"source": "start", "dest": "dec"}, {"source": "start", "dest": "extra"},
166
+ {"source": "dec", "dest": "x"}, {"source": "x", "dest": "stop1"}, # dead-end
167
+ {"source": "dec", "dest": "cont"}, {"source": "cont", "dest": "join"},
168
+ {"source": "extra", "dest": "join"}, {"source": "join", "dest": "stop2"},
169
+ ]
170
+ p = engine.layout(nodes, edges)["positions"]
171
+ assert p["x"]["x"] == p["stop1"]["x"] == p["dec"]["x"] # folded into dec's column
172
+ assert p["cont"]["x"] > p["dec"]["x"] # spine continues horizontally
173
+
174
+
175
+ def test_long_deadend_chain_stays_horizontal():
176
+ # a 4-node dead-end chain (> FOLD_MAX) is NOT folded — laid out as a horizontal lane
177
+ chain = ["c1", "c2", "c3", "stopL"]
178
+ nodes = [{"id": i} for i in ["start", "dec", "cont", "join", "extra", "stop2"] + chain]
179
+ edges = [
180
+ {"source": "start", "dest": "dec"}, {"source": "start", "dest": "extra"},
181
+ {"source": "dec", "dest": "c1"}, {"source": "c1", "dest": "c2"},
182
+ {"source": "c2", "dest": "c3"}, {"source": "c3", "dest": "stopL"},
183
+ {"source": "dec", "dest": "cont"}, {"source": "cont", "dest": "join"},
184
+ {"source": "extra", "dest": "join"}, {"source": "join", "dest": "stop2"},
185
+ ]
186
+ p = engine.layout(nodes, edges, opts={"FOLD_MAX": 2})["positions"] # threshold below len
187
+ xs = [p[c]["x"] for c in chain]
188
+ assert xs == sorted(xs) and len(set(xs)) == 4 # distinct increasing columns
189
+
190
+
191
+ def test_cluster_chains_serpentine_opt_in():
192
+ # a 7-action chain stays one long row by default; with CLUSTER it folds to a serpentine
193
+ nodes = [{"id": f"n{i}"} for i in range(7)]
194
+ edges = [{"source": f"n{i}", "dest": f"n{i + 1}"} for i in range(6)]
195
+ plain = engine.layout(nodes, edges)["positions"]
196
+ assert len({round(p["y"]) for p in plain.values()}) == 1 # one row
197
+ assert len({round(p["x"]) for p in plain.values()}) == 7 # seven columns
198
+ clustered = engine.layout(nodes, edges, opts={"CLUSTER": True})["positions"]
199
+ assert len({round(p["x"]) for p in clustered.values()}) < 7 # fewer columns
200
+ assert len({round(p["y"]) for p in clustered.values()}) > 1 # multiple rows
201
+ # short chains (< CLUSTER_MIN) are NOT clustered
202
+ short = [{"id": f"m{i}"} for i in range(3)]
203
+ se = [{"source": f"m{i}", "dest": f"m{i + 1}"} for i in range(2)]
204
+ sc = engine.layout(short, se, opts={"CLUSTER": True})["positions"]
205
+ assert len({round(p["y"]) for p in sc.values()}) == 1 # stays one row
206
+
207
+
208
+ def _count_norm_crossings(positions, edges):
209
+ E = [(e["source"], e["dest"]) for e in edges if int(e.get("type", 0) or 0) == 0
210
+ and e["source"] in positions and e["dest"] in positions]
211
+
212
+ def orient(p, q, r):
213
+ return (q["y"] - p["y"]) * (r["x"] - q["x"]) - (q["x"] - p["x"]) * (r["y"] - q["y"])
214
+
215
+ def inter(a, b, c, d):
216
+ return (orient(a, b, c) > 0) != (orient(a, b, d) > 0) and \
217
+ (orient(c, d, a) > 0) != (orient(c, d, b) > 0)
218
+ P = positions
219
+ n = 0
220
+ for i in range(len(E)):
221
+ s, d = E[i]
222
+ for j in range(i + 1, len(E)):
223
+ s2, d2 = E[j]
224
+ if len({s, d, s2, d2}) < 4:
225
+ continue
226
+ if inter(P[s], P[d], P[s2], P[d2]):
227
+ n += 1
228
+ return n
229
+
230
+
231
+ def test_minimize_crossings_never_worse_and_opt_in():
232
+ # a spine with a skip-edge + an error region — the pattern that produces crossings
233
+ nodes = [{"id": i} for i in ("start", "d", "a", "b", "join", "e", "stop", "stop2")]
234
+ edges = [
235
+ {"source": "start", "dest": "d"},
236
+ {"source": "d", "dest": "join"}, # long skip edge
237
+ {"source": "d", "dest": "a"}, {"source": "a", "dest": "b"},
238
+ {"source": "b", "dest": "join"},
239
+ {"source": "a", "dest": "e", "type": 1}, {"source": "e", "dest": "stop2"},
240
+ {"source": "join", "dest": "stop"},
241
+ ]
242
+ plain = engine.layout(nodes, edges)["positions"]
243
+ mc = engine.layout(nodes, edges, opts={"MINIMIZE_CROSSINGS": True})["positions"]
244
+ assert _count_norm_crossings(mc, edges) <= _count_norm_crossings(plain, edges) # never worse
245
+ assert engine.layout(nodes, edges)["positions"] == plain # off by default (no-op)
246
+
247
+
248
+ def test_engine_partial_moves_only_subset():
249
+ # a -> b -> c with current positions; b is parked far off. Re-tidy only b.
250
+ nodes = [{"id": "a", "position": {"x": 0, "y": 100}},
251
+ {"id": "b", "position": {"x": 5000, "y": 9000}},
252
+ {"id": "c", "position": {"x": 520, "y": 100}}]
253
+ edges = [{"source": "a", "dest": "b"}, {"source": "b", "dest": "c"}]
254
+ res = engine.layout(nodes, edges, subset=["b"])
255
+ # a and c are untouched
256
+ assert res["positions"]["a"] == {"x": 0.0, "y": 100.0}
257
+ assert res["positions"]["c"] == {"x": 520.0, "y": 100.0}
258
+ # b is placed between its neighbours, at their median y
259
+ assert 0 < res["positions"]["b"]["x"] < 520
260
+ assert abs(res["positions"]["b"]["y"] - 100.0) < 1
261
+
262
+
263
+ def test_engine_partial_deterministic():
264
+ nodes = [{"id": "a", "position": {"x": 0, "y": 0}},
265
+ {"id": "b", "position": {"x": 9, "y": 9}},
266
+ {"id": "c", "position": {"x": 600, "y": 0}}]
267
+ edges = [{"source": "a", "dest": "b"}, {"source": "b", "dest": "c"}]
268
+ assert engine.layout(nodes, edges, subset=["b"]) == \
269
+ engine.layout(copy.deepcopy(nodes), copy.deepcopy(edges), subset=["b"])
270
+
271
+
272
+ @pytest.mark.parametrize("path", sorted(glob.glob(os.path.join(EXPORTS, "*.procesio")))[:3])
273
+ def test_adapter_only_touches_target(path):
274
+ bundle = json.load(open(path, encoding="utf-8"))
275
+ fid = _first_multiaction_flow(bundle)
276
+ if not fid:
277
+ pytest.skip("no multi-action flow")
278
+ flow = next(f for f in bundle["Flows"] if f["Id"] == fid)
279
+ # pick an action that has at least one edge (so it actually relocates)
280
+ edged = {p["SourceId"] for a in flow["Actions"] for p in a.get("Ports") or []} | \
281
+ {p["DestinationId"] for a in flow["Actions"] for p in a.get("Ports") or []}
282
+ target = next((a["Id"] for a in flow["Actions"] if a["Id"] in edged), flow["Actions"][0]["Id"])
283
+ before = copy.deepcopy(bundle)
284
+ res = adapter.layout_flow(bundle, flow_id=fid, only=[target])
285
+ out = res["bundle"]
286
+ assert bundle == before # input untouched (pure)
287
+ bflow = next(f for f in before["Flows"] if f["Id"] == fid)
288
+ aflow = next(f for f in out["Flows"] if f["Id"] == fid)
289
+ b_by = {a["Id"]: a for a in bflow["Actions"]}
290
+ a_by = {a["Id"]: a for a in aflow["Actions"]}
291
+ for aid in b_by:
292
+ if aid == target:
293
+ # only CustomData.position may differ on the target
294
+ bclean = {k: v for k, v in b_by[aid]["CustomData"].items() if k != "position"}
295
+ aclean = {k: v for k, v in a_by[aid]["CustomData"].items() if k != "position"}
296
+ assert bclean == aclean
297
+ else:
298
+ assert b_by[aid] == a_by[aid] # every other action byte-identical
299
+ assert bflow.get("CanvasData") == aflow.get("CanvasData") # viewport untouched
300
+ assert res["nodes_moved"] == 1
301
+
302
+
303
+ def test_container_children_written_relative_and_render_ok():
304
+ # a For-Each area child's position must be stored RELATIVE to the area frame, and the
305
+ # rendered children must land inside the frame (the PROCESIO container convention).
306
+ flow = {"Id": "f", "Actions": [
307
+ {"Id": "start", "ActionTemplateName": "Start",
308
+ "CustomData": {"type": "circle", "position": {"x": 0, "y": 0}},
309
+ "Ports": [{"SourceId": "start", "DestinationId": "loop", "Type": 0}]},
310
+ {"Id": "loop", "ActionTemplateName": "For Each",
311
+ "CustomData": {"type": "area", "name": "For Each", "position": {"x": 0, "y": 0},
312
+ "areaSize": {"width": 0, "height": 0, "x": 0, "y": 0}},
313
+ "Ports": [{"SourceId": "loop", "DestinationId": "k1", "Type": 0},
314
+ {"SourceId": "loop", "DestinationId": "stop", "Type": 0}]},
315
+ {"Id": "k1", "ActionTemplateName": "Map Data", "ParentId": "loop",
316
+ "CustomData": {"type": "square", "position": {"x": 0, "y": 0}},
317
+ "Ports": [{"SourceId": "k1", "DestinationId": "k2", "Type": 0}]},
318
+ {"Id": "k2", "ActionTemplateName": "Add", "ParentId": "loop",
319
+ "CustomData": {"type": "square", "position": {"x": 0, "y": 0}}, "Ports": []},
320
+ {"Id": "stop", "ActionTemplateName": "Stop",
321
+ "CustomData": {"type": "circle", "position": {"x": 0, "y": 0}}, "Ports": []},
322
+ ]}
323
+ out = adapter.layout_flow(flow)["bundle"]
324
+ assert adapter.verify_render(out)["ok"] # children render inside frame
325
+ byid = {a["Id"]: a for a in out["Actions"]}
326
+ asz = byid["loop"]["CustomData"]["areaSize"]
327
+ for kid in ("k1", "k2"): # stored relative, within frame
328
+ p = byid[kid]["CustomData"]["position"]
329
+ assert 0 <= p["x"] <= asz["width"] and 0 <= p["y"] <= asz["height"]
330
+ # first child leaves room for the implicit ForEach-Start (>= one DX from frame left)
331
+ assert min(byid[k]["CustomData"]["position"]["x"] for k in ("k1", "k2")) >= 160
332
+
333
+
334
+ def test_loop_back_edge_returns_vertically():
335
+ # a -> dec -> b -> u, with u looping back to a (retry pattern). The back-edge source u
336
+ # should align under its target a (vertical return), in a lane below.
337
+ nodes = [{"id": i} for i in ("start", "a", "dec", "b", "u", "stop")]
338
+ edges = [{"source": "start", "dest": "a"}, {"source": "a", "dest": "dec"},
339
+ {"source": "dec", "dest": "b"}, {"source": "b", "dest": "u"},
340
+ {"source": "u", "dest": "a"}, # back-edge (loop return)
341
+ {"source": "dec", "dest": "stop"}]
342
+ p = engine.layout(nodes, edges)["positions"]
343
+ assert abs(p["u"]["x"] - p["a"]["x"]) < 1 # u aligned under target a
344
+ assert p["u"]["y"] > p["a"]["y"] # in a lane below
345
+
346
+
347
+ def test_wide_container_does_not_overlap_neighbours():
348
+ # a wide area node next to normal nodes must not overlap them (column spacing accounts
349
+ # for node width). verify_render catches overlaps.
350
+ flow = {"Id": "f", "Actions": [
351
+ {"Id": "s", "ActionTemplateName": "Start",
352
+ "CustomData": {"type": "circle", "position": {"x": 0, "y": 0}},
353
+ "Ports": [{"SourceId": "s", "DestinationId": "loop", "Type": 0}]},
354
+ {"Id": "loop", "ActionTemplateName": "For Each",
355
+ "CustomData": {"type": "area", "name": "For Each", "position": {"x": 0, "y": 0},
356
+ "areaSize": {"width": 0, "height": 0, "x": 0, "y": 0}},
357
+ "Ports": [{"SourceId": "loop", "DestinationId": "k1", "Type": 0},
358
+ {"SourceId": "loop", "DestinationId": "e", "Type": 0}]},
359
+ {"Id": "k1", "ActionTemplateName": "Map Data", "ParentId": "loop",
360
+ "CustomData": {"type": "square", "position": {"x": 0, "y": 0}},
361
+ "Ports": [{"SourceId": "k1", "DestinationId": "k2", "Type": 0}]},
362
+ {"Id": "k2", "ActionTemplateName": "Add", "ParentId": "loop",
363
+ "CustomData": {"type": "square", "position": {"x": 0, "y": 0}}, "Ports": []},
364
+ {"Id": "e", "ActionTemplateName": "Stop",
365
+ "CustomData": {"type": "circle", "position": {"x": 0, "y": 0}}, "Ports": []},
366
+ ]}
367
+ assert adapter.verify_render(adapter.layout_flow(flow)["bundle"])["ok"]
368
+
369
+
370
+ def test_full_relayout_anchors_start_in_place():
371
+ # a full re-layout must keep Start exactly where it was (so the viewport still frames it)
372
+ flow = {"Id": "f", "Actions": [
373
+ {"Id": "start", "ActionTemplateName": "Start",
374
+ "CustomData": {"type": "circle", "position": {"x": -1600, "y": 140}},
375
+ "Ports": [{"SourceId": "start", "DestinationId": "a", "Type": 0}]},
376
+ {"Id": "a", "ActionTemplateName": "Map Data",
377
+ "CustomData": {"type": "square", "position": {"x": -1400, "y": 140}},
378
+ "Ports": [{"SourceId": "a", "DestinationId": "stop", "Type": 0}]},
379
+ {"Id": "stop", "ActionTemplateName": "Stop",
380
+ "CustomData": {"type": "circle", "position": {"x": -1200, "y": 140}}, "Ports": []},
381
+ ]}
382
+ out = adapter.layout_flow(flow)["bundle"]
383
+ sp = next(x for x in out["Actions"] if x["Id"] == "start")["CustomData"]["position"]
384
+ assert sp == {"x": -1600.0, "y": 140.0} # Start unmoved; the rest flows from it
385
+
386
+
387
+ def test_resource_map():
388
+ # a tiny 2-flow bundle where flow A calls flow B
389
+ bundle = {"Flows": [
390
+ {"Id": "A", "Title": "Caller", "Actions": [
391
+ {"Id": "n1", "ActionTemplateName": "Call Subprocess",
392
+ "CustomData": {"type": "square", "configuration": [{"settings": [
393
+ {"label": "Select Subprocess", "type": "flow-list", "value": "B"}]}]},
394
+ "Ports": []}]},
395
+ {"Id": "B", "Title": "Callee", "Actions": []},
396
+ ]}
397
+ rm = adapter.layout_resource_map(bundle)
398
+ ids = {n["flow_id"] for n in rm["nodes"]}
399
+ assert ids == {"A", "B"}
400
+ assert {"source": "A", "target": "B", "kind": "call"} in rm["edges"]
401
+ # caller is left of callee
402
+ pos = {n["flow_id"]: n["x"] for n in rm["nodes"]}
403
+ assert pos["A"] < pos["B"]
404
+
405
+
406
+
407
+ def _bundle_crossings(bundle, flow_id=None):
408
+ """Render-faithful crossing count for a laid-out bundle: children resolved to absolute,
409
+ area nodes attached at frame top-left, all normal+error edges."""
410
+ flows = bundle.get("Flows") or bundle.get("flows") or ([bundle["flow"]] if "flow" in bundle else [bundle])
411
+ def g(d, *ks):
412
+ for k in ks:
413
+ if k in d:
414
+ return d[k]
415
+ return None
416
+ flow = flows[0] if flow_id is None else next((f for f in flows if g(f, "Id", "id") == flow_id), flows[0])
417
+ acts = g(flow, "Actions", "actions") or []
418
+ byid = {g(a, "Id", "id"): a for a in acts}
419
+ def cd(a):
420
+ return g(a, "CustomData", "customData") or {}
421
+ def pos_of(a):
422
+ p = g(cd(a), "position") or {}
423
+ return {"x": float(p.get("x", 0)), "y": float(p.get("y", 0))}
424
+ pos = {g(a, "Id", "id"): pos_of(a) for a in acts}
425
+ kind = {g(a, "Id", "id"): (cd(a).get("type")) for a in acts}
426
+ for a in acts:
427
+ par = g(a, "ParentId", "parentId"); aid = g(a, "Id", "id")
428
+ if par in byid and (cd(byid[par]).get("type")) == "area":
429
+ pp = pos[par]; pos[aid] = {"x": pp["x"] + pos[aid]["x"], "y": pp["y"] + pos[aid]["y"]}
430
+ edges = []
431
+ for a in acts:
432
+ for pt in (g(a, "Ports", "ports") or []):
433
+ s2 = g(pt, "SourceId", "sourceId"); d2 = g(pt, "DestinationId", "destinationId")
434
+ if s2 in pos and d2 in pos and s2 != d2:
435
+ edges.append((s2, d2))
436
+ def orient(p, q, r):
437
+ return (q["y"] - p["y"]) * (r["x"] - q["x"]) - (q["x"] - p["x"]) * (r["y"] - q["y"])
438
+ def si(a, b, c, d):
439
+ return (orient(a, b, c) > 0) != (orient(a, b, d) > 0) and (orient(c, d, a) > 0) != (orient(c, d, b) > 0)
440
+ n = 0
441
+ for i in range(len(edges)):
442
+ s, d = edges[i]
443
+ for j in range(i + 1, len(edges)):
444
+ s2, d2 = edges[j]
445
+ if len({s, d, s2, d2}) < 4:
446
+ continue
447
+ if si(pos[s], pos[d], pos[s2], pos[d2]):
448
+ n += 1
449
+ return n
450
+
451
+ def test_minimize_crossings_reduces_and_stays_local():
452
+ """The optional pass must REDUCE crossings via local/compact moves and NEVER teleport a
453
+ node far into empty space. C->D crosses A->B; a small endpoint nudge clears it."""
454
+ nodes = [{"id": x, "w": 48, "h": 48} for x in ("A", "B", "C", "D")]
455
+ typed = [("A", "B", 0), ("C", "D", 0)]
456
+ DX, DY = engine.DEFAULTS["DX"], engine.DEFAULTS["DY"]
457
+ base = {"A": {"x": 0.0, "y": 0.0}, "B": {"x": 6 * DX, "y": 0.0},
458
+ "C": {"x": 5 * DX, "y": -0.5 * DY}, "D": {"x": 6 * DX, "y": 0.5 * DY}}
459
+
460
+ def crossings(P):
461
+ E = [("A", "B"), ("C", "D")]
462
+ return sum(1 for i in range(len(E)) for j in range(i + 1, len(E))
463
+ if len(set(E[i]) | set(E[j])) == 4
464
+ and engine._seg_int(P[E[i][0]], P[E[i][1]], P[E[j][0]], P[E[j][1]]))
465
+
466
+ def run(pen):
467
+ P = copy.deepcopy(base)
468
+ o = dict(engine.DEFAULTS); o["MINCROSS_MOVE_PENALTY"] = pen
469
+ engine._minimize_crossings(P, [dict(n) for n in nodes], typed, o, movable={"C", "D"})
470
+ return P
471
+
472
+ assert crossings(base) == 1
473
+ Pd = run(0.25)
474
+ assert crossings(Pd) == 0 # it actually fixes it
475
+ step = max(abs(Pd[n]["x"] - base[n]["x"]) / DX + abs(Pd[n]["y"] - base[n]["y"]) / DY
476
+ for n in ("C", "D"))
477
+ assert step <= 3 # via a LOCAL move, not a teleport
478
+ assert run(50.0) == base # heavy penalty pins everything
479
+
480
+
481
+ def test_minimize_crossings_never_worse_on_corpus():
482
+ """On every real export flow, the optional pass must never INCREASE crossings vs base
483
+ (the render-faithful count, area nodes attached at their frame top-left)."""
484
+ import glob as _glob
485
+ for path in sorted(_glob.glob(os.path.join(EXPORTS, "*.procesio")))[:4]:
486
+ bundle = json.load(open(path, encoding="utf-8"))
487
+ fid = _first_multiaction_flow(bundle)
488
+ if not fid:
489
+ continue
490
+ b0 = adapter.layout_flow(bundle, flow_id=fid)["bundle"]
491
+ b1 = adapter.layout_flow(bundle, flow_id=fid, minimize_crossings=True)["bundle"]
492
+ assert _bundle_crossings(b1, fid) <= _bundle_crossings(b0, fid)
493
+
494
+ def test_loop_curl_aligns_retry_loop():
495
+ """A retry/error loop region (entry edge from main + return edge back to main) lays out as
496
+ two vertical columns aligned to its anchors: decisional + fail path above the entry source,
497
+ loop tail above the return target -- so both boundary edges are vertical (no crossing) and
498
+ the decisional reads in-flow."""
499
+ P = {"src": {"x": 1000.0, "y": 500.0}, "ret": {"x": 800.0, "y": 500.0},
500
+ "dec": {"x": 0.0, "y": 0.0}, "t1": {"x": 0.0, "y": 0.0}, "exit": {"x": 0.0, "y": 0.0},
501
+ "f1": {"x": 0.0, "y": 0.0}, "f2": {"x": 0.0, "y": 0.0}}
502
+ rset = {"dec", "t1", "exit", "f1", "f2"}
503
+ typed = [("src", "dec", 1), # entry (error) from main
504
+ ("dec", "t1", 0), ("t1", "exit", 0), ("exit", "ret", 0), # loop -> back to main
505
+ ("dec", "f1", 0), ("f1", "f2", 0)] # fail path
506
+ o = dict(engine.DEFAULTS)
507
+ out = engine._loop_curl(rset, typed, P, o)
508
+ assert out is not None and set(out) == rset
509
+ assert out["dec"]["x"] == P["src"]["x"] # decisional above its entry source
510
+ assert out["exit"]["x"] == P["ret"]["x"] # loop tail above the return target
511
+ assert out["t1"]["x"] == P["ret"]["x"]
512
+ assert out["f1"]["x"] == P["src"]["x"] and out["f1"]["y"] < out["dec"]["y"] # fail above dec
513
+ # both boundary edges vertical -> src->dec and exit->ret cannot cross each other
514
+ assert not engine._seg_int(P["src"], out["dec"], out["exit"], P["ret"])
515
+
516
+
517
+ def test_loop_curl_none_without_return_edge():
518
+ """No return-to-main edge -> not a loop; _loop_curl declines (falls back to flush)."""
519
+ P = {"src": {"x": 100.0, "y": 100.0}, "dec": {"x": 0.0, "y": 0.0}, "a": {"x": 0.0, "y": 0.0}}
520
+ typed = [("src", "dec", 1), ("dec", "a", 0)]
521
+ assert engine._loop_curl({"dec", "a"}, typed, P, dict(engine.DEFAULTS)) is None
522
+
523
+ def test_resolve_overlaps_separates_and_is_noop_when_clean():
524
+ """De-overlap pushes coincident nodes apart (grid-aligned) and is a NO-OP when clean."""
525
+ by_id = {i: {"w": 48, "h": 48} for i in ("a", "b", "c")}
526
+ DY = engine.DEFAULTS["DY"]
527
+ # a and b coincide; c is clear
528
+ pos = {"a": {"x": 0.0, "y": 0.0}, "b": {"x": 0.0, "y": 0.0}, "c": {"x": 500.0, "y": 0.0}}
529
+ engine._resolve_overlaps(pos, by_id, {"a", "b", "c"}, dict(engine.DEFAULTS))
530
+ assert engine._count_overlaps(pos, by_id, list(pos)) == 0
531
+ # clean input untouched
532
+ clean = {"a": {"x": 0.0, "y": 0.0}, "b": {"x": 0.0, "y": DY}, "c": {"x": 500.0, "y": 0.0}}
533
+ before = {k: dict(v) for k, v in clean.items()}
534
+ engine._resolve_overlaps(clean, by_id, {"a", "b", "c"}, dict(engine.DEFAULTS))
535
+ assert clean == before
536
+
537
+
538
+ def test_layout_never_leaves_overlaps_on_corpus():
539
+ """After a full layout (both optional layers on) no two nodes overlap, on real exports."""
540
+ import glob as _glob
541
+ for path in sorted(_glob.glob(os.path.join(EXPORTS, "*.procesio")))[:4]:
542
+ bundle = json.load(open(path, encoding="utf-8"))
543
+ fid = _first_multiaction_flow(bundle)
544
+ if not fid:
545
+ continue
546
+ out = adapter.layout_flow(bundle, flow_id=fid, cluster=True, minimize_crossings=True)
547
+ v = adapter.verify_render(out["bundle"], flow_id=fid)
548
+ assert v.get("issue_count", 0) == 0, (path, v.get("issues"))
549
+
550
+
551
+
552
+ def test_ufold_mid_spine_pocket():
553
+ """The reference ANAF pattern: a long private mid-spine chain folds into a vertical U-pocket --
554
+ entry and exit stay on the spine row, the pocket hangs BELOW in columns, and the
555
+ downstream compacts LEFT by the reclaimed width (unit-level: _fold_run ufold mode)."""
556
+ run = [f"c{i}" for i in range(7)]
557
+ ids = ["a"] + run + ["z0", "z1", "j"]
558
+ ns = [{"id": i, "parent_id": None, "kind": "square"} for i in ids]
559
+ pos = {"a": {"x": 0.0, "y": 0.0}}
560
+ for i in range(7):
561
+ pos[f"c{i}"] = {"x": (i + 1) * 160.0, "y": 0.0}
562
+ pos["z0"] = {"x": 1280.0, "y": 0.0}
563
+ pos["z1"] = {"x": 1440.0, "y": 0.0}
564
+ pos["j"] = {"x": 1280.0, "y": -180.0} # second feeder ABOVE -> pocket clear
565
+ typed = ([("a", "c0", 0), ("c6", "z0", 0), ("j", "z0", 0), ("z0", "z1", 0)]
566
+ + [(f"c{i}", f"c{i + 1}", 0) for i in range(6)])
567
+ o = dict(engine.DEFAULTS)
568
+ r = engine._fold_run(dict(pos), run, ns, typed, o, mode="ufold")
569
+ assert r is not None
570
+ assert round(r["c0"]["y"]) == round(r["c6"]["y"]) == 0 # entry AND exit on the spine row
571
+ assert len({round(r[f"c{i}"]["x"]) for i in range(7)}) == 2 # folded to two columns
572
+ assert all(r[f"c{i}"]["y"] >= -1 for i in range(7)) # pocket hangs BELOW
573
+ assert r["z0"]["x"] < pos["z0"]["x"] # downstream compacted LEFT
574
+ assert r["j"] == pos["j"] # non-downstream feeder untouched