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,568 @@
1
+ """Opt-in ELK 'layered' (Sugiyama) canvas layout — a drop-in alternative to engine.py.
2
+
3
+ WHAT THIS IS
4
+ ------------
5
+ A second, independent auto-layout implementation with the *exact same I/O contract* as
6
+ `engine.layout` (positions = absolute node CENTERS, areas = absolute container frames,
7
+ plus a bbox). It maps the PROCESIO node/edge graph onto the Eclipse Layout Kernel's
8
+ `layered` algorithm (elkjs) and translates the result back. The legacy engine is untouched
9
+ and remains the default; this one is selected via the LAYOUT_ENGINE flag (see dispatch.py).
10
+
11
+ HOW TO FLIP THE FLAG
12
+ --------------------
13
+ setx LAYOUT_ENGINE elk # or: $env:LAYOUT_ENGINE = "elk" (this shell)
14
+ LAYOUT_ENGINE=elk python ... # bash
15
+
16
+ `dispatch.layout()` reads it: `elk` → this module; anything else / unset → legacy. Nothing
17
+ in the UI or tool.yaml changes.
18
+
19
+ HOW IT RUNS (process boundary)
20
+ ------------------------------
21
+ The legacy engine runs backend-side, in-process, synchronously. There is no pure-Python
22
+ ELK, so ELK runs backend-side too: elkjs is invoked through a *synchronous* Node subprocess
23
+ (`elk/elk_runner.mjs`), offline (no network). If Node or elkjs is unavailable, or ELK errors
24
+ on a graph, this module logs and DEGRADES GRACEFULLY to the legacy engine — callers always
25
+ get a valid layout.
26
+
27
+ TUNING FOR READABILITY
28
+ ----------------------
29
+ All ELK knobs are named constants just below, each commented. The layout is tuned for a clean,
30
+ untangled left-to-right process flow: NETWORK_SIMPLEX layering aligns parallel branches,
31
+ Brandes-Köpf BALANCED placement straightens chains, wrapping is OFF (a wide scrollable flow
32
+ reads better than stacked bands), and disconnected sub-flows are packed close. Top-level
33
+ spacing is NODE_NODE_SPACING / NODE_NODE_BETWEEN_LAYERS; inside For-Each containers it is
34
+ CONTAINER_BETWEEN_LAYERS / CONTAINER_NODE_NODE. To bound width instead, set
35
+ WRAPPING_STRATEGY="SINGLE_EDGE" and re-add an aspect ratio — at the cost of fragmenting read.
36
+ """
37
+ from __future__ import annotations
38
+
39
+ import json
40
+ import os
41
+ import shutil
42
+ import subprocess
43
+ import sys
44
+ from pathlib import Path
45
+
46
+ from tools.procesio.layout import engine # reused ONLY for graceful fallback; never mutated
47
+
48
+ # ---------------------------------------------------------------------------
49
+ # ELK tunables — all named + commented so the width/height tradeoff is easy to tweak.
50
+ # ---------------------------------------------------------------------------
51
+ ALGORITHM = "layered" # the Sugiyama layered algorithm.
52
+ DIRECTION = "RIGHT" # left-to-right flow, matching the PROCESIO canvas.
53
+ # Layering: NETWORK_SIMPLEX minimises total edge length, which ALIGNS parallel branches and
54
+ # keeps chains on one rank line (longest-path staggers them). The biggest readability win.
55
+ LAYERING_STRATEGY = "NETWORK_SIMPLEX"
56
+ # Wrapping OFF → a clean, uninterrupted left-to-right flow. Wrapping ("SINGLE_EDGE" +
57
+ # an aspect ratio) bounds width by folding long runs into stacked rows, but for process
58
+ # flows that fragments the read; a wide, scrollable, untangled flow is more understandable.
59
+ WRAPPING_STRATEGY = "OFF"
60
+ # Crossing minimisation: barycenter/median layer-sweep passes.
61
+ CROSSING_MIN_STRATEGY = "LAYER_SWEEP"
62
+ # Node placement: Brandes-Köpf balanced coordinates with BALANCED alignment — straightens
63
+ # chains and centres parallel branches (groups consecutive actions into one run).
64
+ NODE_PLACEMENT_STRATEGY = "BRANDES_KOEPF"
65
+ BK_ALIGNMENT = "BALANCED"
66
+ # Lay each disconnected sub-flow out on its own, then pack them CLOSE (componentComponent
67
+ # gap) instead of scattering them across the canvas with huge empty gaps.
68
+ SEPARATE_COMPONENTS = "true"
69
+ COMPONENT_SPACING = 50
70
+ # Post-compaction pulls nodes left to squeeze out slack, shortening long edges.
71
+ POST_COMPACTION = "LEFT"
72
+ # Lay compound (container) contents out in the SAME layered pass as their parents, so edges
73
+ # that cross hierarchy levels (a For-Each container ↔ its inner actions) are legal and routed.
74
+ # Without this ELK rejects a container→child edge (UnsupportedGraphException).
75
+ HIERARCHY_HANDLING = "INCLUDE_CHILDREN"
76
+ # Spacing (px). node-node = VERTICAL gap between action rows sharing a rank; between-layers =
77
+ # HORIZONTAL gap between ranks (also the room after a decisional, and for its branch labels).
78
+ # Calibrated to the user's hand-layout (row gaps ~120-160; branch labels need horizontal room).
79
+ NODE_NODE_SPACING = 130
80
+ NODE_NODE_BETWEEN_LAYERS = 120
81
+ # Inner padding of a compound (For-Each) container. Extra room on the LEFT leaves space for
82
+ # the implicit ForEach-Start, mirroring the legacy container convention. ELK format string.
83
+ CONTAINER_PADDING = "[top=52,left=104,bottom=100,right=48]"
84
+ # Spacing INSIDE a compound container. Larger than the top-level between-layers so the
85
+ # container's inner action chain doesn't cram its labels together (a real readability defect
86
+ # on For-Each bodies). Tune these up if inner labels still collide.
87
+ CONTAINER_BETWEEN_LAYERS = 150
88
+ CONTAINER_NODE_NODE = 70
89
+ # Minimum For-Each frame (px). A floor so a 1-2 node For-Each still has room; larger bodies
90
+ # grow past it from content + padding. Matches the user's hand-sized container (~W791 H200).
91
+ CONTAINER_MIN_W = 320
92
+ CONTAINER_MIN_H = 200
93
+ # Clustering: fold a straight run of MORE THAN CLUSTER_MIN consecutive 1-in / 1-out actions
94
+ # (Start/Stop included; NOT inside a For-Each; a branch/merge/error-port breaks the run) into a
95
+ # compact serpentine block — down a column of CLUSTER_WRAP, up the next — so a long linear chain
96
+ # stops sprawling the canvas wide. The block is reserved to ELK as ONE node, so no overlaps.
97
+ CLUSTER_ENABLED = True
98
+ CLUSTER_MIN = 6 # cluster runs LONGER than this (>= 7 nodes); 6-node entry spines stay
99
+ # horizontal, matching the reference hand-layout of the ANAF entry
100
+ CLUSTER_WRAP = 4 # nodes stacked per serpentine column before wrapping
101
+ CLUSTER_DX = 170 # serpentine column spacing (centre→centre)
102
+ CLUSTER_DY = 150 # serpentine row spacing (centre→centre)
103
+ # PROCESIO branch conventions (post-ELK): an error-port target, and a decisional's DEFAULT
104
+ # target that leads to a dead-end (Stop/Throw/private chain, NOT a Join and not a rejoining
105
+ # path), is moved PERPENDICULAR to the flow — directly above/below its source (same x) — with
106
+ # its private chain continuing right along that lane. Default→Join and a default that rejoins
107
+ # the main flow stay in-flow. PERP_LANE_GAP is the vertical offset to that lane.
108
+ BRANCH_CONVENTIONS = True
109
+ PERP_LANE_GAP = 185
110
+ # A DEFAULT branch only drops perpendicular when it goes ~directly to a terminal (a stop-branch,
111
+ # chain <= SHORT_DEADEND). A LONGER default chain is the decisional's main processing path and
112
+ # stays IN-FLOW. Error ports always drop perpendicular regardless of length.
113
+ SHORT_DEADEND = 2
114
+ # Fixed seed → deterministic output (same graph in → same layout out), matching the legacy
115
+ # engine's determinism guarantee.
116
+ RANDOM_SEED = 1
117
+
118
+ DEFAULT_W = 48.0
119
+ DEFAULT_H = 48.0
120
+
121
+ _RUNNER = Path(__file__).with_name("elk") / "elk_runner.mjs"
122
+ _SUBPROCESS_TIMEOUT = 60 # seconds; a runaway ELK run must not hang the tool
123
+
124
+
125
+ def _log(msg: str) -> None:
126
+ """Progress/diagnostics go to stderr only (stdout is reserved for tool JSON)."""
127
+ print(f"[elk_engine] {msg}", file=sys.stderr)
128
+
129
+
130
+ # ---------------------------------------------------------------------------
131
+ # node normalisation — same dimension source as the legacy engine's _node()
132
+ # ---------------------------------------------------------------------------
133
+
134
+ def _norm(n: dict) -> dict:
135
+ pos = n.get("position") or {"x": n.get("x", 0.0), "y": n.get("y", 0.0)}
136
+ w = n.get("width") or (n.get("size") or {}).get("w") or DEFAULT_W
137
+ h = n.get("height") or (n.get("size") or {}).get("h") or DEFAULT_H
138
+ try:
139
+ w = float(w) or DEFAULT_W
140
+ except (TypeError, ValueError):
141
+ w = DEFAULT_W
142
+ try:
143
+ h = float(h) or DEFAULT_H
144
+ except (TypeError, ValueError):
145
+ h = DEFAULT_H
146
+ return {
147
+ "id": n["id"],
148
+ "w": w,
149
+ "h": h,
150
+ "parent_id": n.get("parent_id"),
151
+ "kind": n.get("kind") or n.get("shape"),
152
+ "pos": {"x": float((pos or {}).get("x", 0.0) or 0.0),
153
+ "y": float((pos or {}).get("y", 0.0) or 0.0)},
154
+ }
155
+
156
+
157
+ # ---------------------------------------------------------------------------
158
+ # graph translation: PROCESIO nodes/edges -> ELK graph JSON
159
+ # ---------------------------------------------------------------------------
160
+
161
+ def _ancestors(nid: str, parent_of: dict) -> list[str]:
162
+ """[nid, parent, ..., 'root'] — the id's ancestor chain up to the synthetic root."""
163
+ chain = [nid]
164
+ seen = {nid}
165
+ cur = parent_of.get(nid, "root")
166
+ while True:
167
+ chain.append(cur)
168
+ if cur == "root" or cur in seen:
169
+ break
170
+ seen.add(cur)
171
+ cur = parent_of.get(cur, "root")
172
+ return chain
173
+
174
+
175
+ def _lca(a: str, b: str, parent_of: dict) -> str:
176
+ """Lowest common ancestor of two node ids in the containment tree. An edge is declared
177
+ in its endpoints' LCA so hierarchy-crossing edges (container -> child) stay legal."""
178
+ aset = set(_ancestors(a, parent_of))
179
+ for x in _ancestors(b, parent_of):
180
+ if x in aset:
181
+ return x
182
+ return "root"
183
+
184
+
185
+ def _build_elk_graph(nodes: list[dict], edges: list[dict],
186
+ extra_opts: dict | None = None) -> dict:
187
+ """Translate normalised nodes + raw edges into the ELK graph JSON the runner consumes.
188
+
189
+ - Each action -> an ELK node with its real width/height.
190
+ - A node that has children -> an ELK COMPOUND node (children nested, laid out recursively
191
+ by ELK); its own size is left for ELK to compute from its contents.
192
+ - Each connection -> an ELK edge (direction preserved). Back/cycle edges are passed
193
+ through unchanged — the layered algorithm resolves cycles internally.
194
+ - Ports are intentionally NOT modelled: the PROCESIO JSON carries no per-connector
195
+ attachment points (edge endpoints are node ids), so inventing ports would be wrong.
196
+ """
197
+ by_id = {n["id"]: n for n in nodes}
198
+ parent_of = {n["id"]: (n["parent_id"] if n["parent_id"] in by_id else "root")
199
+ for n in nodes}
200
+ children_of: dict[str, list[str]] = {"root": []}
201
+ for n in nodes:
202
+ children_of.setdefault(parent_of[n["id"]], []).append(n["id"])
203
+ children_of.setdefault(n["id"], children_of.get(n["id"], []))
204
+
205
+ # bucket edges by the container they must be declared in (their endpoints' LCA)
206
+ edges_in: dict[str, list[dict]] = {}
207
+ dropped = 0
208
+ for i, e in enumerate(sorted(edges, key=lambda e: (str(e.get("source")),
209
+ str(e.get("dest")),
210
+ int(e.get("type", 0) or 0)))):
211
+ s, d = e.get("source"), e.get("dest")
212
+ if s not in by_id or d not in by_id or s == d:
213
+ dropped += 1
214
+ continue
215
+ host = _lca(s, d, parent_of)
216
+ edges_in.setdefault(host, []).append(
217
+ {"id": f"e{i}", "sources": [s], "targets": [d]})
218
+ if dropped:
219
+ _log(f"dropped {dropped} edge(s) with a missing endpoint or self-loop")
220
+
221
+ def build_node(nid: str) -> dict:
222
+ kids = sorted(children_of.get(nid, []))
223
+ node: dict = {"id": nid}
224
+ if kids:
225
+ # compound: nest children, let ELK size the frame from its contents, and recurse
226
+ # the layered layout inside with the same tunables.
227
+ node["children"] = [build_node(k) for k in kids]
228
+ node["layoutOptions"] = {
229
+ "elk.padding": CONTAINER_PADDING,
230
+ # inherit the root's algorithm/direction/hierarchyHandling (one layered pass
231
+ # across the hierarchy); just size the frame from its contents.
232
+ "elk.hierarchyHandling": "INHERIT",
233
+ # roomier spacing inside the container so its inner chain's labels don't cram
234
+ "elk.layered.spacing.nodeNodeBetweenLayers": str(CONTAINER_BETWEEN_LAYERS),
235
+ "elk.spacing.nodeNode": str(CONTAINER_NODE_NODE),
236
+ }
237
+ else:
238
+ node["width"] = by_id[nid]["w"]
239
+ node["height"] = by_id[nid]["h"]
240
+ if nid in edges_in:
241
+ node["edges"] = edges_in[nid]
242
+ return node
243
+
244
+ root = {
245
+ "id": "root",
246
+ "layoutOptions": {
247
+ "elk.algorithm": ALGORITHM,
248
+ "elk.direction": DIRECTION,
249
+ "elk.hierarchyHandling": HIERARCHY_HANDLING,
250
+ "elk.layered.layering.strategy": LAYERING_STRATEGY,
251
+ "elk.layered.wrapping.strategy": WRAPPING_STRATEGY,
252
+ "elk.layered.crossingMinimization.strategy": CROSSING_MIN_STRATEGY,
253
+ "elk.layered.nodePlacement.strategy": NODE_PLACEMENT_STRATEGY,
254
+ "elk.layered.nodePlacement.bk.fixedAlignment": BK_ALIGNMENT,
255
+ "elk.separateConnectedComponents": SEPARATE_COMPONENTS,
256
+ "elk.spacing.componentComponent": str(COMPONENT_SPACING),
257
+ "elk.layered.compaction.postCompaction.strategy": POST_COMPACTION,
258
+ "elk.layered.spacing.nodeNodeBetweenLayers": str(NODE_NODE_BETWEEN_LAYERS),
259
+ "elk.spacing.nodeNode": str(NODE_NODE_SPACING),
260
+ "elk.spacing.edgeNode": "25",
261
+ "elk.layered.spacing.edgeNodeBetweenLayers": "30",
262
+ "elk.randomSeed": str(RANDOM_SEED),
263
+ },
264
+ "children": [build_node(nid) for nid in sorted(children_of["root"])],
265
+ }
266
+ # optional per-call overrides (opts["elk"]) — for tuning without editing the constants.
267
+ # A None value REMOVES that option key entirely.
268
+ for k, v in (extra_opts or {}).items():
269
+ if v is None:
270
+ root["layoutOptions"].pop(k, None)
271
+ else:
272
+ root["layoutOptions"][k] = str(v)
273
+ if "root" in edges_in:
274
+ root["edges"] = edges_in["root"]
275
+ return root
276
+
277
+
278
+ # ---------------------------------------------------------------------------
279
+ # run ELK (synchronous Node subprocess) + translate coordinates back
280
+ # ---------------------------------------------------------------------------
281
+
282
+ def _run_elk(graph: dict) -> dict:
283
+ """Invoke elkjs via the Node runner. Returns the laid-out graph, or raises on any
284
+ failure (missing node/elkjs, timeout, ELK error) so the caller can fall back."""
285
+ node = shutil.which("node")
286
+ if not node:
287
+ raise RuntimeError("node executable not found on PATH")
288
+ if not _RUNNER.exists():
289
+ raise RuntimeError(f"elk runner missing: {_RUNNER}")
290
+ proc = subprocess.run(
291
+ [node, str(_RUNNER)],
292
+ input=json.dumps(graph).encode("utf-8"),
293
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
294
+ timeout=_SUBPROCESS_TIMEOUT,
295
+ )
296
+ out = proc.stdout.decode("utf-8", "replace").strip()
297
+ if not out:
298
+ raise RuntimeError(f"elk runner produced no output (exit {proc.returncode}); "
299
+ f"stderr: {proc.stderr.decode('utf-8', 'replace')[:400]}")
300
+ laid = json.loads(out)
301
+ if isinstance(laid, dict) and laid.get("error"):
302
+ raise RuntimeError(f"elk runner error: {laid['error']}")
303
+ if proc.returncode != 0:
304
+ raise RuntimeError(f"elk runner exit {proc.returncode}")
305
+ return laid
306
+
307
+
308
+ def _harvest(laid: dict) -> tuple[dict, dict]:
309
+ """Walk the laid-out ELK graph, accumulating absolute offsets, and produce the legacy
310
+ contract: positions = absolute node CENTERS (every node incl. compounds + children),
311
+ areas = absolute container frames (top-left + size)."""
312
+ positions: dict = {}
313
+ areas: dict = {}
314
+
315
+ def walk(node: dict, off_x: float, off_y: float) -> None:
316
+ for child in node.get("children", []) or []:
317
+ # ELK x/y are the child's top-left RELATIVE to this node's content origin.
318
+ tlx = off_x + float(child.get("x", 0.0) or 0.0)
319
+ tly = off_y + float(child.get("y", 0.0) or 0.0)
320
+ kids = child.get("children") or []
321
+ if kids:
322
+ w = max(float(child.get("width", DEFAULT_W) or DEFAULT_W), CONTAINER_MIN_W)
323
+ h = max(float(child.get("height", DEFAULT_H) or DEFAULT_H), CONTAINER_MIN_H)
324
+ areas[child["id"]] = {"x": tlx, "y": tly, "width": w, "height": h}
325
+ positions[child["id"]] = {"x": tlx + w / 2, "y": tly + h / 2}
326
+ walk(child, tlx, tly) # children are positioned inside this frame
327
+ else:
328
+ w = float(child.get("width", DEFAULT_W) or DEFAULT_W)
329
+ h = float(child.get("height", DEFAULT_H) or DEFAULT_H)
330
+ positions[child["id"]] = {"x": tlx + w / 2, "y": tly + h / 2}
331
+
332
+ walk(laid, float(laid.get("x", 0.0) or 0.0), float(laid.get("y", 0.0) or 0.0))
333
+ return positions, areas
334
+
335
+
336
+ # ---------------------------------------------------------------------------
337
+ # serpentine clustering of long straight runs (pre-collapse → ELK → expand)
338
+ # ---------------------------------------------------------------------------
339
+
340
+ def _serpentine_size(k: int) -> tuple[float, float]:
341
+ cols = (k + CLUSTER_WRAP - 1) // CLUSTER_WRAP
342
+ rows = min(k, CLUSTER_WRAP)
343
+ return (cols - 1) * CLUSTER_DX + DEFAULT_W, (rows - 1) * CLUSTER_DY + DEFAULT_H
344
+
345
+
346
+ def _find_straight_runs(ns: list[dict], edges: list[dict]) -> list[list[str]]:
347
+ """Maximal chains of top-level, 1-in/1-out actions (Start/Stop included) connected by
348
+ private edges, NOT inside a For-Each. A branch (out>1, incl. an error port), a merge
349
+ (in>1), or a container boundary ends the run. Only runs longer than CLUSTER_MIN returned."""
350
+ by = {n["id"]: n for n in ns}
351
+ area_ids = {n["id"] for n in ns if n["kind"] == "area"}
352
+ ids = set(by)
353
+ indeg = {i: 0 for i in ids}
354
+ outdeg = {i: 0 for i in ids}
355
+ norm = []
356
+ for e in (edges or []):
357
+ s, d, tp = e.get("source"), e.get("dest"), int(e.get("type", 0) or 0)
358
+ if s in ids and d in ids and s != d:
359
+ outdeg[s] += 1 # counts normal AND error edges → an error handler = branch
360
+ indeg[d] += 1
361
+ if tp == 0:
362
+ norm.append((s, d))
363
+
364
+ def straight(nid):
365
+ n = by[nid]
366
+ return (n["kind"] != "area" and n["parent_id"] not in area_ids
367
+ and indeg[nid] <= 1 and outdeg[nid] <= 1)
368
+
369
+ nnext, nprev = {}, {}
370
+ for s, d in norm:
371
+ if straight(s) and straight(d):
372
+ nnext[s] = d
373
+ nprev[d] = s
374
+ runs, seen = [], set()
375
+ for s in sorted(u for u in ids if straight(u) and u in nnext and u not in nprev):
376
+ if s in seen:
377
+ continue
378
+ run, cur = [s], s
379
+ seen.add(s)
380
+ while cur in nnext and nnext[cur] not in seen:
381
+ cur = nnext[cur]
382
+ run.append(cur)
383
+ seen.add(cur)
384
+ if len(run) > CLUSTER_MIN:
385
+ runs.append(run)
386
+ return runs
387
+
388
+
389
+ def _collapse_runs(ns, edges, runs):
390
+ """Replace each run with one meta-node sized as its serpentine block; rewire edges to it."""
391
+ node_to_meta, metas, meta_map = {}, [], {}
392
+ for k, run in enumerate(runs):
393
+ mid = f"__cluster{k}"
394
+ w, h = _serpentine_size(len(run))
395
+ metas.append({"id": mid, "w": w, "h": h, "parent_id": None, "kind": None,
396
+ "pos": {"x": 0.0, "y": 0.0}})
397
+ meta_map[mid] = run
398
+ for nid in run:
399
+ node_to_meta[nid] = mid
400
+ run_nodes = set(node_to_meta)
401
+ new_ns = [n for n in ns if n["id"] not in run_nodes] + metas
402
+ new_edges, seen_e = [], set()
403
+ for e in (edges or []):
404
+ s, d, tp = e.get("source"), e.get("dest"), int(e.get("type", 0) or 0)
405
+ ms, md = node_to_meta.get(s, s), node_to_meta.get(d, d)
406
+ if ms == md or (ms, md, tp) in seen_e:
407
+ continue
408
+ seen_e.add((ms, md, tp))
409
+ new_edges.append({"source": ms, "dest": md, "type": tp})
410
+ return new_ns, new_edges, meta_map
411
+
412
+
413
+ def _expand_serpentine(positions: dict, mid: str, run: list[str]) -> None:
414
+ """Replace a placed meta-node with its run laid out as a serpentine inside the block."""
415
+ c = positions.pop(mid)
416
+ w, h = _serpentine_size(len(run))
417
+ mx, my = c["x"] - w / 2, c["y"] - h / 2
418
+ rows = min(len(run), CLUSTER_WRAP)
419
+ for i, nid in enumerate(run):
420
+ col, r = i // CLUSTER_WRAP, i % CLUSTER_WRAP
421
+ row = r if col % 2 == 0 else (rows - 1 - r) # boustrophedon: down, then up
422
+ positions[nid] = {"x": mx + DEFAULT_W / 2 + col * CLUSTER_DX,
423
+ "y": my + DEFAULT_H / 2 + row * CLUSTER_DY}
424
+
425
+
426
+ # ---------------------------------------------------------------------------
427
+ # PROCESIO branch conventions: error / default-dead-end targets -> perpendicular lane
428
+ # ---------------------------------------------------------------------------
429
+
430
+ def _lane_collides(cand: dict, others: dict, by: dict) -> bool:
431
+ for cid, cp in cand.items():
432
+ cw = by.get(cid, {}).get("w", DEFAULT_W)
433
+ ch = by.get(cid, {}).get("h", DEFAULT_H)
434
+ for oid, op in others.items():
435
+ ow = by.get(oid, {}).get("w", DEFAULT_W)
436
+ oh = by.get(oid, {}).get("h", DEFAULT_H)
437
+ if abs(cp["x"] - op["x"]) < (cw + ow) / 2 and abs(cp["y"] - op["y"]) < (ch + oh) / 2 + 1:
438
+ return True
439
+ return False
440
+
441
+
442
+ def _apply_branch_conventions(positions: dict, ns: list[dict], edges: list[dict]) -> dict:
443
+ """Move error / default-dead-end targets to a perpendicular lane at the source's column.
444
+ A dead-end = a private chain that ends in a terminal WITHOUT passing through a merge (Join);
445
+ so default->Join and a default that rejoins the flow return no chain and stay in-flow.
446
+ Loop-backs (target upstream) and For-Each members are left alone. Collision-checked; if no
447
+ clear lane is found the chain is left where ELK placed it (safe no-op)."""
448
+ by = {n["id"]: n for n in ns}
449
+ ids = set(by)
450
+ area_ids = {n["id"] for n in ns if n["kind"] == "area"}
451
+
452
+ def movable(nid):
453
+ return nid in by and by[nid]["kind"] != "area" and by[nid]["parent_id"] not in area_ids
454
+
455
+ norm_succ, indeg_norm = {}, {}
456
+ for e in edges:
457
+ s, d, tp = e["source"], e["dest"], int(e.get("type", 0) or 0)
458
+ if tp == 0 and s in ids and d in ids and s != d:
459
+ norm_succ.setdefault(s, []).append(d)
460
+ indeg_norm[d] = indeg_norm.get(d, 0) + 1
461
+
462
+ def deadend(tgt):
463
+ chain, cur = [], tgt
464
+ while True:
465
+ if indeg_norm.get(cur, 0) > 1: # a merge (Join) -> rejoins the flow
466
+ return None
467
+ chain.append(cur)
468
+ outs = [d for d in norm_succ.get(cur, []) if d in ids]
469
+ if not outs:
470
+ return chain # terminal -> private dead-end chain
471
+ if len(outs) > 1 or outs[0] in chain:
472
+ return None # branches / cycle -> not a simple dead-end
473
+ cur = outs[0]
474
+
475
+ DX = NODE_NODE_BETWEEN_LAYERS + DEFAULT_W
476
+ moves = []
477
+ for e in edges:
478
+ s, d, tp = e["source"], e["dest"], int(e.get("type", 0) or 0)
479
+ if s not in ids or d not in ids or s == d or s not in positions or d not in positions:
480
+ continue
481
+ if not (tp == 1 or bool(e.get("is_default"))):
482
+ continue
483
+ if positions[d]["x"] < positions[s]["x"] - 24: # loop-back -> leave in place
484
+ continue
485
+ if not movable(s):
486
+ continue
487
+ chain = deadend(d)
488
+ if chain and all(movable(c) for c in chain):
489
+ if tp == 1 or len(chain) <= SHORT_DEADEND: # error: always; default: stop-branch only
490
+ moves.append((s, chain))
491
+
492
+ moved = set()
493
+ for s, chain in sorted(moves, key=lambda m: positions[m[0]]["x"]):
494
+ if any(c in moved for c in chain):
495
+ continue
496
+ sx, sy = positions[s]["x"], positions[s]["y"]
497
+ for mult in range(1, 10):
498
+ done = False
499
+ for direction in (1, -1): # prefer below, then above
500
+ lane_y = sy + direction * mult * PERP_LANE_GAP
501
+ cand = {chain[i]: {"x": sx + i * DX, "y": lane_y} for i in range(len(chain))}
502
+ others = {i: positions[i] for i in positions if i not in chain}
503
+ if not _lane_collides(cand, others, by):
504
+ positions.update(cand)
505
+ moved.update(chain)
506
+ done = True
507
+ break
508
+ if done:
509
+ break
510
+ return positions
511
+
512
+
513
+ # ---------------------------------------------------------------------------
514
+ # public entry: same signature as engine.layout
515
+ # ---------------------------------------------------------------------------
516
+
517
+ def layout(nodes: list[dict], edges: list[dict], opts: dict | None = None,
518
+ subset: list[str] | None = None) -> dict:
519
+ """Lay out a node/edge graph with ELK 'layered'. Same contract as engine.layout:
520
+ returns {positions:{id:{x,y}}, areas:{id:{x,y,width,height}}, bbox}.
521
+
522
+ `subset` (partial re-tidy) is a legacy-only capability (ELK is not incremental), so a
523
+ subset request is delegated to the legacy engine. Any ELK failure also falls back to
524
+ legacy — the caller always gets a valid layout."""
525
+ if subset is not None:
526
+ _log("subset/partial re-tidy requested → delegating to legacy engine (ELK is not "
527
+ "incremental)")
528
+ return engine.layout(nodes, edges, opts=opts, subset=subset)
529
+
530
+ ns = [_norm(n) for n in nodes]
531
+ if not ns:
532
+ return {"positions": {}, "areas": {},
533
+ "bbox": {"minX": 0, "minY": 0, "maxX": 0, "maxY": 0}}
534
+
535
+ # pre-collapse long straight runs into serpentine meta-nodes (ELK reserves their space)
536
+ runs = _find_straight_runs(ns, edges or []) if CLUSTER_ENABLED else []
537
+ cns, cedges, meta_map = (_collapse_runs(ns, edges or [], runs) if runs
538
+ else (ns, list(edges or []), {}))
539
+ if runs:
540
+ _log(f"clustered {len(runs)} straight run(s) of sizes {[len(r) for r in runs]}")
541
+
542
+ try:
543
+ graph = _build_elk_graph(cns, cedges, extra_opts=(opts or {}).get("elk"))
544
+ laid = _run_elk(graph)
545
+ positions, areas = _harvest(laid)
546
+ for mid, run in meta_map.items(): # expand each serpentine block in place
547
+ if mid in positions:
548
+ _expand_serpentine(positions, mid, run)
549
+ if BRANCH_CONVENTIONS:
550
+ _apply_branch_conventions(positions, ns, edges or [])
551
+ except Exception as exc: # noqa: BLE001 — any ELK failure must degrade, not crash
552
+ _log(f"ELK layout failed ({type(exc).__name__}: {exc}); falling back to legacy engine")
553
+ return engine.layout(nodes, edges, opts=opts, subset=subset)
554
+
555
+ # guard: every input node must have landed with finite coordinates; otherwise fall back
556
+ missing = [n["id"] for n in ns if n["id"] not in positions]
557
+ bad = [i for i, p in positions.items()
558
+ if not (isinstance(p["x"], float) and isinstance(p["y"], float))
559
+ or p["x"] != p["x"] or p["y"] != p["y"]] # NaN self-inequality
560
+ if missing or bad:
561
+ _log(f"ELK output incomplete (missing={missing[:5]} nan={bad[:5]}); "
562
+ f"falling back to legacy engine")
563
+ return engine.layout(nodes, edges, opts=opts, subset=subset)
564
+
565
+ xs = [p["x"] for p in positions.values()] or [0]
566
+ ys = [p["y"] for p in positions.values()] or [0]
567
+ return {"positions": positions, "areas": areas,
568
+ "bbox": {"minX": min(xs), "minY": min(ys), "maxX": max(xs), "maxY": max(ys)}}