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,256 @@
1
+ """Adding a control to a LIVE form (flowmodel-free: dto/form/addelement).
2
+
3
+ Why this exists: `form-create` speaks an authoring config, `form-edit` rebuilds a form from one, and
4
+ neither can add a control to a form that was hand-built in the designer — the two shapes are
5
+ different languages (the create config has no element ids at all). Everything else in the toolkit is
6
+ surgical (set one config, wire one event); adding a control was the missing verb, so a new admin
7
+ button meant hand-writing a stored element DTO.
8
+
9
+ The invariant that makes it safe: PROCESIO backs every control with a data-model sub-model whose id
10
+ is the ELEMENT id and whose attribute ids are the ELEMENT'S OWN CONFIG IDS. So new controls can be
11
+ SPLICED into the live `Data.dataModel` without touching what is already there — which matters,
12
+ because a RUN_PROCESS map references a field by the path `root.fields.elementId.valueAttrId`, and
13
+ regenerating those ids would break every existing mapping on the form.
14
+ """
15
+ from __future__ import annotations
16
+
17
+ import copy
18
+
19
+ import pytest
20
+
21
+ from tools.procesio.dto.form import addelement
22
+ from tools.procesio.errors import UsageError
23
+
24
+
25
+ ROOT = "65396456-36bf-4d9f-8d32-63a4a9e5c8c0"
26
+ FIELDS_NS = "11223344-5566-7788-99aa-aabbccddeeff"
27
+ EXISTING_EL = "aaaaaaaa-1111-1111-1111-111111111111"
28
+ EXISTING_CFG = "bbbbbbbb-2222-2222-2222-222222222222"
29
+
30
+
31
+ def _live_form() -> dict:
32
+ """A form as GET /api/FormTemplate/{id} returns it, with one existing control."""
33
+ return {
34
+ "id": "form-1", "name": "Admin", "isPrivate": True, "type": 1, "status": 1,
35
+ "state": True, "assignees": [], "customUrl": None,
36
+ "data": {
37
+ "elements": [
38
+ {"id": EXISTING_EL, "type": "input", "section": "body", "parentId": None,
39
+ "category": "field",
40
+ "configs": [{"id": EXISTING_CFG, "key": "value", "label": "Value", "value": ""},
41
+ {"id": "cccccccc-3333-3333-3333-333333333333", "key": "name",
42
+ "label": "Name", "value": "DefaultTimeZone"}]},
43
+ ],
44
+ "variables": [{"id": ROOT, "dataType": ROOT, "name": "form", "type": 20}],
45
+ "dataModel": {
46
+ "id": ROOT, "name": "form", "attributes": [
47
+ {"id": FIELDS_NS, "dataTypeId": FIELDS_NS, "name": "fields",
48
+ "parentDataTypeId": ROOT, "isDataModel": True, "attributes": [
49
+ {"id": EXISTING_EL, "dataTypeId": EXISTING_EL, "name": "DefaultTimeZone",
50
+ "parentDataTypeId": FIELDS_NS, "isDataModel": True, "attributes": [
51
+ {"id": EXISTING_CFG, "name": "value", "parentDataTypeId": EXISTING_EL}]},
52
+ ]},
53
+ ]},
54
+ },
55
+ }
56
+
57
+
58
+ def _fields_attrs(data: dict) -> list:
59
+ fields = next(a for a in data["dataModel"]["attributes"] if a["id"] == FIELDS_NS)
60
+ return fields["attributes"]
61
+
62
+
63
+ def _by_name(elements: list, name: str):
64
+ for el in elements:
65
+ for c in el.get("configs", []):
66
+ if c.get("key") == "name" and c.get("value") == name:
67
+ return el
68
+ return None
69
+
70
+
71
+ # --------------------------------------------------------------------------- the happy path
72
+
73
+ def test_a_new_control_is_appended_to_the_elements_list():
74
+ form = _live_form()
75
+ out = addelement.add_elements(form, [{"type": "input", "label": "Organiser Email",
76
+ "name": "OrganiserEmail"}])
77
+
78
+ assert len(out["elements"]) == 2
79
+ added = _by_name(out["elements"], "OrganiserEmail")
80
+ assert added is not None and added["type"] == "input"
81
+
82
+
83
+ def test_the_existing_control_is_untouched_down_to_its_config_ids():
84
+ form = _live_form()
85
+ before = copy.deepcopy(form["data"]["elements"][0])
86
+
87
+ out = addelement.add_elements(form, [{"type": "input", "name": "OrganiserEmail"}])
88
+
89
+ assert out["elements"][0] == before
90
+
91
+
92
+ def test_every_existing_data_model_id_survives():
93
+ """A RUN_PROCESS map references root.fields.elementId.valueAttrId — regenerating any of those
94
+ ids silently breaks every mapping already on the form."""
95
+ form = _live_form()
96
+ out = addelement.add_elements(form, [{"type": "input", "name": "OrganiserEmail"}])
97
+
98
+ existing = next(s for s in _fields_attrs(out) if s["id"] == EXISTING_EL)
99
+ assert existing["attributes"][0]["id"] == EXISTING_CFG
100
+ assert out["dataModel"]["id"] == ROOT
101
+
102
+
103
+ def test_the_new_control_gets_a_sub_model_keyed_by_its_element_id():
104
+ form = _live_form()
105
+ out = addelement.add_elements(form, [{"type": "input", "name": "OrganiserEmail"}])
106
+
107
+ added = _by_name(out["elements"], "OrganiserEmail")
108
+ sub = next((s for s in _fields_attrs(out) if s["id"] == added["id"]), None)
109
+ assert sub is not None
110
+ assert sub["name"] == "OrganiserEmail"
111
+ assert sub["parentDataTypeId"] == FIELDS_NS
112
+
113
+
114
+ def test_the_new_sub_model_attribute_ids_equal_the_new_element_config_ids():
115
+ form = _live_form()
116
+ out = addelement.add_elements(form, [{"type": "input", "name": "OrganiserEmail"}])
117
+
118
+ added = _by_name(out["elements"], "OrganiserEmail")
119
+ sub = next(s for s in _fields_attrs(out) if s["id"] == added["id"])
120
+ cfg_ids = {c["id"] for c in added["configs"]}
121
+ assert {a["id"] for a in sub["attributes"]} <= cfg_ids
122
+ assert any(a["name"] == "value" for a in sub["attributes"]), (
123
+ "the value attribute is what a process map binds to")
124
+
125
+
126
+ # --------------------------------------------------------------------------- placement
127
+
128
+ def test_a_control_can_be_parented_to_an_existing_container():
129
+ form = _live_form()
130
+ form["data"]["elements"].append(
131
+ {"id": "tab-1", "type": "tab", "section": "body", "parentId": None,
132
+ "configs": [{"id": "n1", "key": "name", "value": "Tab1"}]})
133
+
134
+ out = addelement.add_elements(form, [{"type": "button", "label": "Delete", "name": "delBtn"}],
135
+ parent="Tab1")
136
+
137
+ assert _by_name(out["elements"], "delBtn")["parentId"] == "tab-1"
138
+
139
+
140
+ def test_an_unknown_parent_is_refused_and_names_what_exists():
141
+ form = _live_form()
142
+ with pytest.raises(UsageError) as e:
143
+ addelement.add_elements(form, [{"type": "button", "name": "b"}], parent="Nope")
144
+ assert "Nope" in str(e.value)
145
+
146
+
147
+ def test_a_duplicate_control_name_is_refused():
148
+ """Two controls sharing a name make the field-path resolver ambiguous."""
149
+ form = _live_form()
150
+ with pytest.raises(UsageError) as e:
151
+ addelement.add_elements(form, [{"type": "input", "name": "DefaultTimeZone"}])
152
+ assert "DefaultTimeZone" in str(e.value)
153
+
154
+
155
+ def test_several_controls_can_be_added_in_one_call_and_keep_their_order():
156
+ form = _live_form()
157
+ out = addelement.add_elements(form, [
158
+ {"type": "input", "name": "MinimumNoticeHours"},
159
+ {"type": "input", "name": "GoogleCalendarId"},
160
+ {"type": "input", "name": "OrganiserEmail"}])
161
+
162
+ names = [c["value"] for el in out["elements"] for c in el["configs"] if c["key"] == "name"]
163
+ assert names[-3:] == ["MinimumNoticeHours", "GoogleCalendarId", "OrganiserEmail"]
164
+
165
+
166
+ def test_adding_nothing_is_refused_rather_than_writing_the_form_back_unchanged():
167
+ with pytest.raises(UsageError):
168
+ addelement.add_elements(_live_form(), [])
169
+
170
+
171
+ def test_the_form_passed_in_is_not_mutated():
172
+ form = _live_form()
173
+ snapshot = copy.deepcopy(form)
174
+ addelement.add_elements(form, [{"type": "input", "name": "OrganiserEmail"}])
175
+ assert form == snapshot, "the caller decides when to write; the builder stays pure"
176
+
177
+
178
+ # --------------------------------------------------------------------------- container registration
179
+
180
+ def _form_with_tabs() -> dict:
181
+ """A tabs container that draws its children from its own `tabs` list, as the runtime does."""
182
+ form = _live_form()
183
+ form["data"]["elements"].append(
184
+ {"id": "tabs-1", "type": "tabs", "section": "body", "parentId": None,
185
+ "configs": [{"id": "tn", "key": "name", "value": "Tabs1"},
186
+ {"id": "tl", "key": "tabs", "value": ["Tab1"]}]})
187
+ form["data"]["elements"].append(
188
+ {"id": "tab-1", "type": "tab", "section": "body", "parentId": "tabs-1",
189
+ "configs": [{"id": "t1n", "key": "name", "value": "Tab1"}]})
190
+ return form
191
+
192
+
193
+ def test_a_new_tab_is_registered_in_its_container_list():
194
+ """Parenting alone is not enough: a tabs container renders the names in its `tabs` config, so a
195
+ spliced tab that is missing from it exists, saves, lints clean and never appears on screen."""
196
+ out = addelement.add_elements(_form_with_tabs(), [{"type": "tab", "name": "Tab2"}],
197
+ parent="Tabs1")
198
+ tabs = next(e for e in out["elements"] if e["id"] == "tabs-1")
199
+ listed = next(c["value"] for c in tabs["configs"] if c["key"] == "tabs")
200
+ assert listed == ["Tab1", "Tab2"]
201
+
202
+
203
+ def test_a_table_row_is_registered_in_the_table_rows_list():
204
+ form = _live_form()
205
+ form["data"]["elements"].append(
206
+ {"id": "table-1", "type": "table", "section": "body", "parentId": None,
207
+ "configs": [{"id": "tbn", "key": "name", "value": "Table1"},
208
+ {"id": "tbr", "key": "rows", "value": []}]})
209
+ out = addelement.add_elements(form, [{"type": "dynamic-table-row", "name": "Row1"}],
210
+ parent="Table1")
211
+ table = next(e for e in out["elements"] if e["id"] == "table-1")
212
+ assert next(c["value"] for c in table["configs"] if c["key"] == "rows") == ["Row1"]
213
+
214
+
215
+ def test_a_container_with_no_list_config_is_untouched():
216
+ form = _live_form()
217
+ form["data"]["elements"].append(
218
+ {"id": "sec-1", "type": "section", "section": "body", "parentId": None,
219
+ "configs": [{"id": "sn", "key": "name", "value": "Section1"}]})
220
+ out = addelement.add_elements(form, [{"type": "input", "name": "Extra"}], parent="Section1")
221
+ sec = next(e for e in out["elements"] if e["id"] == "sec-1")
222
+ assert [c["key"] for c in sec["configs"]] == ["name"]
223
+
224
+
225
+ def test_an_existing_entry_is_not_duplicated():
226
+ form = _form_with_tabs()
227
+ out = addelement.add_elements(form, [{"type": "tab", "name": "Tab2"}], parent="Tabs1")
228
+ form2 = {"id": "form-1", "data": out}
229
+ out2 = addelement.add_elements(form2, [{"type": "tab", "name": "Tab3"}], parent="Tabs1")
230
+ tabs = next(e for e in out2["elements"] if e["id"] == "tabs-1")
231
+ assert next(c["value"] for c in tabs["configs"] if c["key"] == "tabs") == ["Tab1", "Tab2", "Tab3"]
232
+
233
+
234
+ def test_a_control_placed_inside_a_table_row_is_flagged_as_unreachable():
235
+ """A map cannot read a control that exists once per row, and nothing else reports that."""
236
+ elements = [
237
+ {"id": "tbl", "type": "table", "parentId": None,
238
+ "configs": [{"key": "name", "value": "Table1"}, {"key": "rows", "value": ["Row1"]}]},
239
+ {"id": "row", "type": "dynamic-table-row", "parentId": "tbl",
240
+ "configs": [{"key": "name", "value": "Row1"}]},
241
+ {"id": "panel", "type": "side-panel", "parentId": "row",
242
+ "configs": [{"key": "name", "value": "EditPanel"}]},
243
+ ]
244
+ warning = addelement.unreachable_in_row(elements, "panel")
245
+ assert warning is not None
246
+ assert "Row1" in warning
247
+ assert "$.item" in warning
248
+
249
+
250
+ def test_a_control_outside_any_row_is_not_flagged():
251
+ elements = [
252
+ {"id": "tab", "type": "tab", "parentId": None,
253
+ "configs": [{"key": "name", "value": "Tab1"}]},
254
+ ]
255
+ assert addelement.unreachable_in_row(elements, "tab") is None
256
+ assert addelement.unreachable_in_row(elements, None) is None
@@ -0,0 +1,319 @@
1
+ """Three form gaps measured live on QA on 2026-09-25 while testing Approval Control events.
2
+
3
+ 1. form-create left the top-level `Assignees` empty on a form whose section had an assignee
4
+ and whose approval control had an approver. The designer's save
5
+ (user-playground Builder.component.vue::save + ui-builder utils/formBuilder/payload.ts)
6
+ builds one ASSIGNEE step (type 1) per element with assignee users and one APPROVER step
7
+ (type 2) per element with approver users: `{stepId: <element id>, orderId: n, users:
8
+ [{userId}]}`, orderId counting 1, 2, 3 within each list.
9
+ 2. form-create built a form data model with only `instance, fields` and no
10
+ `dataModelAttributeFormatVersion`. The designer writes `instance, flow, fields,
11
+ preventFormSubmit, browserTitle` and version "1" for a new form. Without the version the
12
+ designer treats the form as the legacy "0" format and LOWER-CASES every field attribute on
13
+ its next save (measured: `RequestText` became `requesttext`); without `preventFormSubmit`
14
+ a form script cannot block a submit.
15
+ 3. form-set-element-event refused to wire an approval trigger on an approval control saved
16
+ before its event slots existed (old forms). The runtime back-fills missing configs from
17
+ the element template on every load (ui-builder utils/formBuilder/elements.ts::
18
+ actualizeElements); the CLI now does the same for the one slot it needs, and says so.
19
+ """
20
+ from __future__ import annotations
21
+
22
+ import json
23
+
24
+ import pytest
25
+
26
+ from tools.procesio import main
27
+ from tools.procesio.client import ProcesioClient
28
+ from tools.procesio.dto.form import builder
29
+ from tools.procesio.errors import UsageError
30
+ from tools.procesio.tests.conftest import FakeResp, FakeSession
31
+
32
+ APIKEY = {"type": "apikey", "key": "N", "value": "V"}
33
+ U1, U2, U3 = "u-1111", "u-2222", "u-3333"
34
+
35
+
36
+ def _call(action, argv, session):
37
+ return main.dispatch(
38
+ action, argv,
39
+ client_builder=lambda prof: ProcesioClient(profile=APIKEY, name="t", session=session))
40
+
41
+
42
+ def _ids():
43
+ n = iter(range(10_000))
44
+ return {"new_id": lambda: f"id-{next(n)}"}
45
+
46
+
47
+ def _by_type(dto, kind):
48
+ return [e for e in dto["Data"]["elements"] if e["type"] == kind]
49
+
50
+
51
+ # --------------------------------------------------------------------------- gap 1
52
+
53
+ def _approval_form(**top):
54
+ return {
55
+ "name": "AUTO approval gaps",
56
+ **top,
57
+ "elements": [
58
+ {"type": "section", "label": "Request", "configs": {"assignee": U1},
59
+ "children": [{"type": "input", "label": "Text", "name": "RequestText"}]},
60
+ {"type": "approval", "label": "Approval step", "name": "Approval1",
61
+ "approver": U2, "configs": {"approverReplacement": [U3, "", U2]}},
62
+ {"type": "button", "label": "Submit", "submit": True},
63
+ ],
64
+ }
65
+
66
+
67
+ def test_assignees_are_derived_from_assignee_and_approver_configs_like_the_designer():
68
+ dto = builder.build(_approval_form(isPrivate=True), _ids())
69
+ section, = _by_type(dto, "section")
70
+ approval, = _by_type(dto, "approval")
71
+ assert dto["Assignees"] == [
72
+ {"stepId": section["id"], "orderId": 1, "type": 1, "users": [{"userId": U1}]},
73
+ # approver first, then replacements; blanks dropped, duplicates collapsed
74
+ {"stepId": approval["id"], "orderId": 1, "type": 2,
75
+ "users": [{"userId": U2}, {"userId": U3}]},
76
+ ]
77
+
78
+
79
+ def test_order_ids_count_within_each_list():
80
+ cfg = _approval_form()
81
+ cfg["elements"].insert(2, {"type": "approval", "label": "Second", "name": "Approval2",
82
+ "approver": U3})
83
+ dto = builder.build(cfg, _ids())
84
+ approvers = [a for a in dto["Assignees"] if a["type"] == 2]
85
+ assert [a["orderId"] for a in approvers] == [1, 2]
86
+ assert [a["users"][0]["userId"] for a in approvers] == [U2, U3]
87
+
88
+
89
+ def test_a_form_with_approvers_becomes_a_user_task_when_type_is_not_given():
90
+ assert builder.build(_approval_form(), _ids())["Type"] == 0
91
+
92
+
93
+ def test_an_explicit_type_is_respected():
94
+ assert builder.build(_approval_form(type="general"), _ids())["Type"] == 1
95
+
96
+
97
+ def test_explicit_assignees_in_the_config_still_win_verbatim():
98
+ mine = [{"stepId": "S", "orderId": 7, "type": 2, "users": [{"userId": "X"}]}]
99
+ assert builder.build(_approval_form(assignees=mine), _ids())["Assignees"] == mine
100
+
101
+
102
+ def test_a_form_without_assignees_is_unchanged():
103
+ dto = builder.build({"name": "plain", "elements": [{"type": "input", "label": "A"}]}, _ids())
104
+ assert dto["Assignees"] == [] and dto["Type"] == 1
105
+
106
+
107
+ # --------------------------------------------------------------------------- gap 2
108
+
109
+ PREVENT = "d63722f4-0cd1-4bc2-8174-28276e7c7ab5"
110
+ TITLE = "b8c1f2a3-4d5e-4a6b-8c7d-9e0f1a2b3c4d"
111
+ FLOW = "c16e9d56-8484-444d-b1c5-36e48afb1d3d"
112
+ INSTANCE = "8b49c48a-0834-40d0-920a-4c53566495a8"
113
+ BOOL, STR = "0317bfee-b2f5-4bde-bfe8-121212121210", "0317bfee-b2f5-4bde-bfe8-121212121214"
114
+
115
+
116
+ def test_data_model_matches_what_the_designer_saves_for_a_new_form():
117
+ dto = builder.build(_approval_form(), _ids())
118
+ data = dto["Data"]
119
+ assert data["dataModelAttributeFormatVersion"] == "1"
120
+ dm = data["dataModel"]
121
+ top = {a["name"]: a for a in dm["attributes"]}
122
+ assert [a["name"] for a in dm["attributes"]] == [
123
+ "instance", "flow", "fields", "preventFormSubmit", "browserTitle"]
124
+ root = data["variables"][0]["id"]
125
+ assert dm["id"] == root
126
+ assert all(a["parentDataTypeId"] == root for a in dm["attributes"])
127
+ assert (top["preventFormSubmit"]["id"], top["preventFormSubmit"]["dataTypeId"]) == (PREVENT, BOOL)
128
+ assert (top["browserTitle"]["id"], top["browserTitle"]["dataTypeId"]) == (TITLE, STR)
129
+ assert top["flow"]["id"] == FLOW and "statusEnum" in [a["name"] for a in top["flow"]["attributes"]]
130
+ assert top["instance"]["id"] == INSTANCE
131
+ assert [a["name"] for a in top["instance"]["attributes"]] == [
132
+ "id", "workspaceId", "submitter", "currentUser"]
133
+ # the fields container still carries one sub-model per element, named as-is (format "1")
134
+ assert "RequestText" in [a["name"] for a in top["fields"]["attributes"]]
135
+
136
+
137
+ # --------------------------------------------------------------------------- gap 3
138
+
139
+ def _old_form():
140
+ """An approval control as saved before its event slots existed (QA form 8d789e26…,
141
+ created 2025-06-03): 15 configs, no onBefore*/onAfter* keys."""
142
+ old_keys = ["label", "tooltip", "description", "info-text", "visible", "comment",
143
+ "responseDate", "responseUser", "response", "name", "id", "approver",
144
+ "approverReplacement", "additionalApprovers", "onInputEvents"]
145
+ configs = [{"id": f"c-{k}", "key": k, "value": None} for k in old_keys]
146
+ next(c for c in configs if c["key"] == "name")["value"] = "Approval1"
147
+ return {
148
+ "id": "F-OLD", "name": "Complex (Copy)", "isPrivate": True, "type": 0, "status": 1,
149
+ "state": True, "assignees": [], "customUrl": None,
150
+ "data": {"code": "", "dataModel": {"id": "dm"}, "elements": [
151
+ {"id": "A1", "type": "approval", "configs": configs},
152
+ {"id": "I1", "type": "input", "configs": [{"id": "c-n", "key": "name", "value": "Input1"}]},
153
+ ]},
154
+ }
155
+
156
+
157
+ _JS = {"code": "console.log($event)"}
158
+
159
+
160
+ def test_a_missing_approval_slot_is_backfilled_from_the_template_and_reported():
161
+ s = FakeSession(queue=[FakeResp(200, _old_form()), FakeResp(200, _old_form()), FakeResp(200, {})])
162
+ out = _call("form-set-element-event",
163
+ ["--id", "F-OLD", "--element", "Approval1", "--on", "beforeapprove",
164
+ "--action", "RUN_JAVASCRIPT", "--config", json.dumps(_JS)], s)
165
+
166
+ assert out["updated"] is True
167
+ assert out["backfilled"] == ["onBeforeApproveEvents"]
168
+ put = s.calls[-1]
169
+ assert put["method"] == "PUT"
170
+ els = put["json"]["Data"]["elements"]
171
+ assert els[1] == _old_form()["data"]["elements"][1] # sibling untouched
172
+ configs = els[0]["configs"]
173
+ slot = [c for c in configs if c["key"] == "onBeforeApproveEvents"]
174
+ assert len(slot) == 1
175
+ assert slot[0]["type"] == "field-events" and slot[0]["id"] not in {c.get("id") for c in _old_form()["data"]["elements"][0]["configs"]}
176
+ assert slot[0]["value"]["events"][0]["type"] == "BEFORE_APPROVE"
177
+ # every existing config survives, in its original order
178
+ assert [c for c in configs if c["key"] != "onBeforeApproveEvents"] == _old_form()["data"]["elements"][0]["configs"]
179
+
180
+
181
+ def test_dry_run_reports_the_backfill_without_writing():
182
+ s = FakeSession(queue=[FakeResp(200, _old_form())])
183
+ out = _call("form-set-element-event",
184
+ ["--id", "F-OLD", "--element", "Approval1", "--on", "afterapprovalsubmit",
185
+ "--action", "RUN_JAVASCRIPT", "--config", json.dumps(_JS), "--dry-run"], s)
186
+ assert out["dry_run"] is True and out["backfilled"] == ["onAfterApprovalSubmitEvents"]
187
+ assert all(c["method"] == "GET" for c in s.calls)
188
+
189
+
190
+ def test_a_trigger_the_element_type_cannot_raise_is_still_refused():
191
+ s = FakeSession(queue=[FakeResp(200, _old_form())])
192
+ with pytest.raises(UsageError, match="cannot raise"):
193
+ _call("form-set-element-event",
194
+ ["--id", "F-OLD", "--element", "Input1", "--on", "beforeapprove",
195
+ "--action", "RUN_JAVASCRIPT", "--config", json.dumps(_JS)], s)
196
+ assert all(c["method"] == "GET" for c in s.calls)
197
+
198
+
199
+ def test_an_existing_slot_is_used_as_is_and_nothing_is_reported_as_backfilled():
200
+ s = FakeSession(queue=[FakeResp(200, _old_form()), FakeResp(200, _old_form()), FakeResp(200, {})])
201
+ out = _call("form-set-element-event",
202
+ ["--id", "F-OLD", "--element", "Approval1", "--on", "input",
203
+ "--action", "RUN_JAVASCRIPT", "--config", json.dumps(_JS)], s)
204
+ assert out["backfilled"] == []
205
+ configs = s.calls[-1]["json"]["Data"]["elements"][0]["configs"]
206
+ assert len(configs) == len(_old_form()["data"]["elements"][0]["configs"])
207
+
208
+
209
+ # --------------------------------------------------------------- dynamic-row approval steps
210
+ # Shape of a real designer-saved "Dynamic Table Approval" form (QA, ids replaced): approval
211
+ # steps live in each dynamic row's `approvalSteps`, and each step is its own APPROVER step.
212
+
213
+ def _cfg_el(eid, etype, parent=None, **configs):
214
+ return {"id": eid, "type": etype, "parentId": parent,
215
+ "configs": [{"key": k, "value": v} for k, v in configs.items()]}
216
+
217
+
218
+ def _step(sid, approver, replacement=None, row_index="0"):
219
+ return {"id": sid, "rowIndex": row_index, "approver": approver,
220
+ "approverReplacement": replacement or []}
221
+
222
+
223
+ def _table_form():
224
+ return [
225
+ _cfg_el("SEC", "section", assignee=U1),
226
+ _cfg_el("T", "table", assignee=U2),
227
+ _cfg_el("R1", "dynamic-table-row", "T", visible=True, approvalSteps=[
228
+ _step("S1", U1), _step("S2", U2, [U3, U2]),
229
+ _step("S-UNPLACED", U3, row_index=None)]), # no rowIndex: not a step
230
+ _cfg_el("R2", "dynamic-table-row", "T", visible=False, # hidden row: no steps
231
+ approvalSteps=[_step("S-HIDDEN", U1)]),
232
+ _cfg_el("R3", "dynamic-table-row", "SEC", # not in a table: no steps
233
+ approvalSteps=[_step("S-ORPHAN", U1)]),
234
+ _cfg_el("A", "approval", approver=U3),
235
+ ]
236
+
237
+
238
+ def test_dynamic_row_approval_steps_are_their_own_steps_like_the_designer():
239
+ rows = builder.derive_assignees(_table_form())
240
+ assert [(r["type"], r["stepId"], r["orderId"], [u["userId"] for u in r["users"]])
241
+ for r in rows] == [
242
+ (1, "SEC", 1, [U1]), (1, "T", 2, [U2]),
243
+ (2, "S1", 1, [U1]), (2, "S2", 2, [U2, U3]), (2, "A", 3, [U3]),
244
+ ]
245
+
246
+
247
+ # --------------------------------------------------------------- surgical edits keep routing true
248
+
249
+ def test_an_edit_that_does_not_change_routing_keeps_the_stored_list_byte_for_byte():
250
+ stale = [{"stepId": "whatever", "orderId": 9, "type": 2, "users": [{"userId": "x"}]}]
251
+ before = [_cfg_el("A", "approval", approver=U1, label="Old")]
252
+ after = [_cfg_el("A", "approval", approver=U1, label="New")]
253
+ assert builder.reconcile_assignees(stale, before, after) == (stale, None)
254
+
255
+
256
+ def test_an_edit_that_changes_routing_rederives_the_whole_list():
257
+ before = [_cfg_el("A", "approval", approver=U1)]
258
+ after = [_cfg_el("A", "approval", approver=U2)]
259
+ saved, report = builder.reconcile_assignees([], before, after)
260
+ assert saved == [{"stepId": "A", "orderId": 1, "type": 2, "users": [{"userId": U2}]}]
261
+ assert report["rederived"] is True and report["after"] == [("A", 1, 2, (U2,))]
262
+
263
+
264
+ def _live_approval_form(**top):
265
+ approver = {"id": "c-appr", "key": "approver", "value": U1}
266
+ return {
267
+ "id": "F-LIVE", "name": "Live", "isPrivate": True, "type": 0, "status": 1, "state": True,
268
+ "customUrl": None,
269
+ "assignees": [{"stepId": "A1", "orderId": 1, "type": 2,
270
+ "users": [{"userId": U1, "firstName": "G", "lastName": "G"}]}],
271
+ "data": {
272
+ "code": "", "variables": [{"id": "root", "dataType": "root", "name": "form"}],
273
+ "dataModel": {"id": "root", "name": "form", "attributes": [
274
+ {"id": "11223344-5566-7788-99aa-aabbccddeeff", "name": "fields",
275
+ "parentDataTypeId": "root", "attributes": []}]},
276
+ "elements": [
277
+ {"id": "A1", "type": "approval", "parentId": None, "section": "body",
278
+ "configs": [{"id": "c-name", "key": "name", "value": "Approval1"},
279
+ {"id": "c-label", "key": "label", "value": "Approve"}, approver]},
280
+ ]},
281
+ **top,
282
+ }
283
+
284
+
285
+ def test_set_element_config_rederives_assignees_when_the_approver_changes():
286
+ s = FakeSession(queue=[FakeResp(200, _live_approval_form()), FakeResp(200, {})])
287
+ out = _call("form-set-element-config",
288
+ ["--id", "F-LIVE", "--element", "Approval1", "--set", f"approver={U2}"], s)
289
+ put = s.calls[-1]["json"]
290
+ assert put["Assignees"] == [{"stepId": "A1", "orderId": 1, "type": 2, "users": [{"userId": U2}]}]
291
+ assert out["assignees"]["rederived"] is True
292
+
293
+
294
+ def test_set_element_config_leaves_assignees_alone_for_a_label_change():
295
+ s = FakeSession(queue=[FakeResp(200, _live_approval_form()), FakeResp(200, {})])
296
+ out = _call("form-set-element-config",
297
+ ["--id", "F-LIVE", "--element", "Approval1", "--set", "label=Check"], s)
298
+ assert s.calls[-1]["json"]["Assignees"] == _live_approval_form()["assignees"] # echoed
299
+ assert "assignees" not in out
300
+
301
+
302
+ def test_add_element_routes_a_new_approval_control():
303
+ s = FakeSession(queue=[FakeResp(200, _live_approval_form()), FakeResp(200, {})])
304
+ spec = {"type": "approval", "name": "Approval2", "approver": U3}
305
+ out = _call("form-add-element", ["--id", "F-LIVE", "--elements", json.dumps(spec)], s)
306
+ put = s.calls[-1]["json"]
307
+ new_id = out["added"][0]["id"]
308
+ assert put["Assignees"] == [
309
+ {"stepId": "A1", "orderId": 1, "type": 2, "users": [{"userId": U1}]},
310
+ {"stepId": new_id, "orderId": 2, "type": 2, "users": [{"userId": U3}]},
311
+ ]
312
+ assert out["assignees"]["rederived"] is True
313
+
314
+
315
+ def test_delete_element_unroutes_a_removed_approval_control():
316
+ s = FakeSession(queue=[FakeResp(200, _live_approval_form()), FakeResp(200, {})])
317
+ out = _call("form-delete-element", ["--id", "F-LIVE", "--element", "Approval1"], s)
318
+ assert s.calls[-1]["json"]["Assignees"] == []
319
+ assert out["assignees"]["rederived"] is True
@@ -0,0 +1,60 @@
1
+ """Auto-generated field names are single lowercase words, stable across a designer save.
2
+
3
+ When a form config gives no explicit `name`, the builder derives one from the label. It
4
+ used to title-case it (`Company Name` -> `CompanyName`), which a designer save re-keys and
5
+ `formlint.lint_field_names` then flags. The builder now makes a single lowercase word, so
6
+ an auto-named field survives a designer save unchanged and does not trip the lint. The
7
+ human-readable text stays in the label, not the name. `_slug` (flowgraph display, which
8
+ keeps case) is a different function and is left alone.
9
+ """
10
+ from __future__ import annotations
11
+
12
+ import itertools
13
+
14
+ from tools.procesio import formlint
15
+ from tools.procesio.dto.form import builder as fb
16
+
17
+
18
+ def _ctx():
19
+ cnt = itertools.count(1)
20
+ return {"new_id": lambda: f"00000000-0000-0000-0000-{next(cnt):012d}"}
21
+
22
+
23
+ def test_field_slug_is_a_single_lowercase_word():
24
+ assert fb._field_slug("Company Name") == "companyname"
25
+ assert fb._field_slug("order_id") == "orderid"
26
+ assert fb._field_slug("Already lower") == "alreadylower"
27
+ assert fb._field_slug("") == "field"
28
+
29
+
30
+ def test_unnamed_elements_get_lowercase_names_that_do_not_trip_the_lint():
31
+ dto = fb.build({"name": "F", "elements": [
32
+ {"type": "input", "label": "Company Name"},
33
+ {"type": "select", "label": "Order List", "options": ["a", "b"]},
34
+ ]}, _ctx())
35
+ data = dto["Data"]
36
+ names = [c["value"] for e in data["elements"] for c in e.get("configs", [])
37
+ if c.get("key") == "name"]
38
+ assert "companyname" in names and "orderlist" in names, names
39
+ assert all(fb._SINGLE_WORD.fullmatch(n) for n in names) if hasattr(fb, "_SINGLE_WORD") \
40
+ else all(n == n.lower() and n.isalnum() for n in names), names
41
+ assert formlint.lint_field_names(data) == []
42
+
43
+
44
+ def test_an_explicit_mixed_case_name_is_left_as_written():
45
+ """Kept verbatim. Since 2026-10-05 the builder writes dataModelAttributeFormatVersion "1",
46
+ and a designer save keeps names at "1" (measured on QA: orderList, order_id and
47
+ Customer_First_Name survived a designer re-publish and form JS saw them as written), so a
48
+ builder-made form draws no warning. The same names on a form WITHOUT the version (legacy
49
+ "0", e.g. one built before that date) still warn."""
50
+ dto = fb.build({"name": "F", "elements": [
51
+ {"type": "input", "label": "x", "name": "OrderList"},
52
+ ]}, _ctx())
53
+ data = dto["Data"]
54
+ names = [c["value"] for e in data["elements"] for c in e.get("configs", [])
55
+ if c.get("key") == "name"]
56
+ assert "OrderList" in names, names
57
+ assert data["dataModelAttributeFormatVersion"] == "1"
58
+ assert formlint.lint_field_names(data) == []
59
+ legacy = {k: v for k, v in data.items() if k != "dataModelAttributeFormatVersion"}
60
+ assert formlint.lint_field_names(legacy), "a form without the version must still warn"