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,826 @@
1
+ """Tests for the surgical node-parameter patcher (flowmodel/nodeparam.py).
2
+
3
+ Guards the two things that make a one-literal edit safe: the string-only scope (a structured
4
+ parameter must be refused, not silently text-patched) and the placeholder contract (the `<%N%>`
5
+ set binds `variable[]` positionally, so it may not drift without an explicit opt-in).
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import pytest
10
+
11
+ from tools.procesio.flowmodel import nodeparam
12
+
13
+ ENDPOINT = "45a7bbde-7e2a-4bd4-a6d3-8420f7790002"
14
+ PAYLOAD = "45a7bbde-7e2a-4bd4-a6d3-8420f7790003"
15
+
16
+
17
+ def _flow():
18
+ """A Call API node shaped like the live DTO: a string Endpoint bound to one variable, plus a
19
+ structured Request Parameters tab, mirrored in the designer side-pannel."""
20
+ return {
21
+ "id": "flow-1", "title": "Rates",
22
+ "variables": [{"id": "var-year", "name": "year", "type": 20}],
23
+ "actions": [
24
+ {"id": "act-1", "actionName": "Get all by year", "actionTemplateName": "Call API",
25
+ "parameters": [
26
+ {"tabPropertyId": ENDPOINT, "value": "https://old.example/x<%0%>.xml",
27
+ "variable": [{"id": 0, "variableId": "var-year", "attribute": None}]},
28
+ {"tabPropertyId": PAYLOAD, "value": {"headers": [], "queryParams": []},
29
+ "variable": []},
30
+ ],
31
+ "customData": {"configuration": [{"settings": [
32
+ {"id": "side", "type": "side-pannel", "label": "Configure Request", "value": [
33
+ {"id": ENDPOINT, "label": "Endpoint", "value": "https://old.example/xvar-year.xml"},
34
+ {"id": PAYLOAD, "label": "Request Parameters", "value": {}},
35
+ ]},
36
+ ]}]}},
37
+ ],
38
+ }
39
+
40
+
41
+ def test_find_node_by_id_and_by_label():
42
+ f = _flow()
43
+ assert nodeparam.find_node(f, "act-1")["id"] == "act-1"
44
+ assert nodeparam.find_node(f, "Get all by year")["id"] == "act-1"
45
+ assert nodeparam.find_node(f, "nope") is None
46
+
47
+
48
+ def test_find_param_by_label_and_by_id():
49
+ n = _flow()["actions"][0]
50
+ assert nodeparam.find_param(n, "Endpoint")["tabPropertyId"] == ENDPOINT
51
+ assert nodeparam.find_param(n, "endpoint")["tabPropertyId"] == ENDPOINT # case-insensitive
52
+ assert nodeparam.find_param(n, ENDPOINT)["tabPropertyId"] == ENDPOINT
53
+ assert nodeparam.find_param(n, "Missing") is None
54
+
55
+
56
+ def test_describe_node_labels_binds_and_editability():
57
+ f = _flow()
58
+ d = nodeparam.describe_node(f, f["actions"][0])
59
+ by_label = {p["label"]: p for p in d["parameters"]}
60
+ assert by_label["Endpoint"]["editable"] is True
61
+ assert by_label["Endpoint"]["binds"] == [{"index": 0, "variable": "year", "id": "var-year"}]
62
+ assert by_label["Request Parameters"]["editable"] is False
63
+ assert by_label["Request Parameters"]["value"] == "<structured>"
64
+
65
+
66
+ def test_set_param_value_rewrites_host_and_keeps_binding():
67
+ f = _flow()
68
+ n = f["actions"][0]
69
+ p = nodeparam.find_param(n, "Endpoint")
70
+ r = nodeparam.set_param_value(n, p, "https://new.example/x<%0%>.xml")
71
+ assert r["changed"] is True
72
+ assert p["value"] == "https://new.example/x<%0%>.xml"
73
+ assert p["variable"] == [{"id": 0, "variableId": "var-year", "attribute": None}]
74
+
75
+
76
+ def test_set_param_value_is_noop_when_identical():
77
+ f = _flow()
78
+ n = f["actions"][0]
79
+ p = nodeparam.find_param(n, "Endpoint")
80
+ assert nodeparam.set_param_value(n, p, p["value"])["changed"] is False
81
+
82
+
83
+ def test_structured_parameter_is_refused():
84
+ f = _flow()
85
+ n = f["actions"][0]
86
+ p = nodeparam.find_param(n, "Request Parameters")
87
+ with pytest.raises(ValueError, match="not text"):
88
+ nodeparam.set_param_value(n, p, "anything")
89
+
90
+
91
+ def test_dropping_a_placeholder_is_refused_unless_opted_in():
92
+ f = _flow()
93
+ n = f["actions"][0]
94
+ p = nodeparam.find_param(n, "Endpoint")
95
+ with pytest.raises(ValueError, match="placeholder set"):
96
+ nodeparam.set_param_value(n, p, "https://new.example/fixed.xml")
97
+ nodeparam.set_param_value(n, p, "https://new.example/fixed.xml", allow_binding_change=True)
98
+ assert p["value"] == "https://new.example/fixed.xml"
99
+
100
+
101
+ def test_placeholders_reports_the_binding_contract():
102
+ assert nodeparam.placeholders("a<%1%>b<%0%>c<%1%>") == [0, 1]
103
+ assert nodeparam.placeholders({"not": "a string"}) == []
104
+
105
+
106
+ def _map_node():
107
+ """A Map Data node shaped like the live DTO: the runtime row holds `<%1%>-12-01`, the designer
108
+ mirror the same literal appended to the variable GUID. The literal is identical in both."""
109
+ return {
110
+ "id": "map-1", "actionName": "set start currentDate", "actionTemplateName": "Map Data",
111
+ "parameters": [{"tabPropertyId": "map-pid", "variable": [], "value": [
112
+ {"id": 0, "slugId": "map-process-data",
113
+ "source": {"value": "<%1%>-12-01", "variable": [{"id": 1, "variableId": "var-year"}]},
114
+ "destination": {"id": 0, "variableId": "var-cur"}},
115
+ {"id": 1, "slugId": "map-process-data",
116
+ "source": {"value": "<%3%>-12-01", "variable": [{"id": 3, "variableId": "var-year"}]},
117
+ "destination": {"id": 2, "variableId": "var-last"}},
118
+ ]}],
119
+ "customData": {"configuration": [{"settings": [
120
+ {"id": "side", "type": "side-pannel", "label": "Map Process Data", "value": [
121
+ {"id": "map-pid", "label": "Map Process Variables", "type": "map-process-data",
122
+ "value": [{"id": 0, "destination": "var-cur", "source": "var-year-12-01"},
123
+ {"id": 1, "destination": "var-last", "source": "var-year-12-01"}]},
124
+ ]},
125
+ ]}]},
126
+ }
127
+
128
+
129
+ def test_replace_text_reaches_both_layers_of_a_structured_parameter():
130
+ n = _map_node()
131
+ hits = nodeparam.replace_text(n, "-12-01", "-01-01")
132
+ assert sum(h["count"] for h in hits) == 4
133
+ assert {h["layer"] for h in hits} == {"runtime", "designer"}
134
+ rows = n["parameters"][0]["value"]
135
+ assert rows[0]["source"]["value"] == "<%1%>-01-01"
136
+ assert rows[1]["source"]["value"] == "<%3%>-01-01"
137
+ designer = n["customData"]["configuration"][0]["settings"][0]["value"][0]["value"]
138
+ assert [r["source"] for r in designer] == ["var-year-01-01", "var-year-01-01"]
139
+
140
+
141
+ def test_replace_text_keeps_variable_bindings_untouched():
142
+ n = _map_node()
143
+ nodeparam.replace_text(n, "-12-01", "-01-01")
144
+ assert n["parameters"][0]["value"][0]["source"]["variable"] == [{"id": 1, "variableId": "var-year"}]
145
+
146
+
147
+ def test_replace_text_reports_nothing_when_the_literal_is_absent():
148
+ n = _map_node()
149
+ assert nodeparam.replace_text(n, "-99-99", "-01-01") == []
150
+
151
+
152
+ def test_replace_text_can_be_narrowed_to_one_property():
153
+ f = _flow()
154
+ n = f["actions"][0]
155
+ hits = nodeparam.replace_text(n, "old.example", "new.example", property_key="Endpoint")
156
+ assert sum(h["count"] for h in hits) == 2 # runtime param + designer mirror
157
+ assert n["parameters"][0]["value"] == "https://new.example/x<%0%>.xml"
158
+
159
+
160
+ def test_replace_text_rejects_an_empty_needle():
161
+ with pytest.raises(ValueError, match="non-empty"):
162
+ nodeparam.replace_text(_map_node(), "", "x")
163
+
164
+
165
+ def _typed_flow():
166
+ return {"id": "f", "title": "T", "actions": [], "variables": [
167
+ {"id": "v-list", "name": "exchangeRateList", "type": 20,
168
+ "dataType": "0317bfee-b2f5-4bde-bfe8-121212121220", "isList": True},
169
+ {"id": "v-out", "name": "exchangeRate", "type": 30,
170
+ "dataType": "0317bfee-b2f5-4bde-bfe8-121212121220", "isList": False},
171
+ {"id": "v-in", "name": "payload", "type": 10,
172
+ "dataType": "0317bfee-b2f5-4bde-bfe8-121212121214", "isList": False},
173
+ ]}
174
+
175
+
176
+ OBJECT = "0317bfee-b2f5-4bde-bfe8-121212121221"
177
+
178
+
179
+ def test_find_variable_by_name_and_id():
180
+ f = _typed_flow()
181
+ assert nodeparam.find_variable(f, "exchangeRateList")["id"] == "v-list"
182
+ assert nodeparam.find_variable(f, "v-out")["name"] == "exchangeRate"
183
+ assert nodeparam.find_variable(f, "ghost") is None
184
+
185
+
186
+ def test_retyping_an_internal_variable_is_allowed():
187
+ f = _typed_flow()
188
+ v = nodeparam.find_variable(f, "exchangeRateList")
189
+ r = nodeparam.set_variable_type(f, v, OBJECT)
190
+ assert r["changed"] is True and r["direction"] == "process"
191
+ assert v["dataType"] == OBJECT and v["isList"] is True # isList untouched when not passed
192
+
193
+
194
+ def test_retyping_an_output_variable_needs_the_contract_override():
195
+ f = _typed_flow()
196
+ v = nodeparam.find_variable(f, "exchangeRate")
197
+ with pytest.raises(ValueError, match="public contract"):
198
+ nodeparam.set_variable_type(f, v, OBJECT)
199
+ nodeparam.set_variable_type(f, v, OBJECT, allow_contract_change=True)
200
+ assert v["dataType"] == OBJECT
201
+
202
+
203
+ def test_retyping_an_input_variable_needs_the_contract_override():
204
+ f = _typed_flow()
205
+ v = nodeparam.find_variable(f, "payload")
206
+ with pytest.raises(ValueError, match="public contract"):
207
+ nodeparam.set_variable_type(f, v, OBJECT)
208
+
209
+
210
+ def test_retype_is_a_noop_when_already_that_type():
211
+ f = _typed_flow()
212
+ v = nodeparam.find_variable(f, "exchangeRateList")
213
+ assert nodeparam.set_variable_type(f, v, v["dataType"], is_list=True)["changed"] is False
214
+
215
+
216
+ def test_clearing_required_on_an_input_needs_no_override():
217
+ """Loosening cannot break a caller: every payload that was valid stays valid."""
218
+ f = _typed_flow()
219
+ v = nodeparam.find_variable(f, "payload")
220
+ v["isRequired"] = True
221
+ r = nodeparam.set_variable_required(f, v, False)
222
+ assert r["changed"] is True and r["direction"] == "input"
223
+ assert v["isRequired"] is False
224
+
225
+
226
+ def test_making_an_input_required_needs_the_contract_override():
227
+ """Tightening breaks every caller that legitimately omitted the field."""
228
+ f = _typed_flow()
229
+ v = nodeparam.find_variable(f, "payload")
230
+ v["isRequired"] = False
231
+ with pytest.raises(ValueError, match="public contract"):
232
+ nodeparam.set_variable_required(f, v, True)
233
+ nodeparam.set_variable_required(f, v, True, allow_contract_change=True)
234
+ assert v["isRequired"] is True
235
+
236
+
237
+ def test_isrequired_is_refused_on_a_non_input_variable():
238
+ """Only an input carries a caller-supplied value, so the flag means nothing elsewhere."""
239
+ f = _typed_flow()
240
+ for name in ("exchangeRate", "exchangeRateList"):
241
+ with pytest.raises(ValueError, match="only an input variable"):
242
+ nodeparam.set_variable_required(f, nodeparam.find_variable(f, name), False)
243
+
244
+
245
+ def test_setting_required_to_its_current_value_is_a_noop():
246
+ f = _typed_flow()
247
+ v = nodeparam.find_variable(f, "payload")
248
+ v["isRequired"] = True
249
+ assert nodeparam.set_variable_required(f, v, True)["changed"] is False
250
+
251
+
252
+ def test_add_variable_appends_and_is_addressable_by_name_and_id():
253
+ f = _typed_flow()
254
+ before = len(f["variables"])
255
+ v = nodeparam.add_variable(f, "historyText", "string", "output")
256
+ assert len(f["variables"]) == before + 1
257
+ assert v["type"] == 30 and v["isList"] is False and v["isRequired"] is False
258
+ assert nodeparam.find_variable(f, "historyText")["id"] == v["id"]
259
+ assert nodeparam.find_variable(f, v["id"])["name"] == "historyText"
260
+
261
+
262
+ def test_add_variable_refuses_a_duplicate_name():
263
+ """The form-event tooling resolves names to ids, so two same-named variables are ambiguous."""
264
+ f = _typed_flow()
265
+ with pytest.raises(ValueError, match="already exists"):
266
+ nodeparam.add_variable(f, "payload", "string", "input")
267
+
268
+
269
+ def test_add_variable_refuses_an_unknown_direction_or_type():
270
+ f = _typed_flow()
271
+ with pytest.raises(ValueError, match="direction must be"):
272
+ nodeparam.add_variable(f, "x", "string", "sideways")
273
+ with pytest.raises(ValueError, match="unknown data type"):
274
+ nodeparam.add_variable(f, "y", "stringy", "output")
275
+
276
+
277
+ def _chain_flow():
278
+ """start -> a -> b -> stop, ports living on the SOURCE action."""
279
+ def port(src, dst):
280
+ return {"id": f"p-{src}-{dst}", "flowId": "f", "sourceId": src, "destinationId": dst}
281
+ return {"id": "f", "title": "T", "variables": [], "actions": [
282
+ {"id": "a", "actionName": "a", "actionTemplateName": "Node", "ports": [port("a", "b")]},
283
+ {"id": "b", "actionName": "b", "actionTemplateName": "Node", "ports": [port("b", "stop")]},
284
+ ]}
285
+
286
+
287
+ def test_insert_node_takes_the_successor_and_repoints_the_anchor():
288
+ """Both edits, or the graph is broken in a way that still validates."""
289
+ f = _chain_flow()
290
+ anchor = f["actions"][0]
291
+ new = {"id": "n", "actionName": "mid", "actionTemplateName": "Node"}
292
+ ok, msg = nodeparam.insert_node(f, anchor, new)
293
+ assert ok and "between" in msg
294
+ assert anchor["ports"][0]["destinationId"] == "n" # anchor now points at the new node
295
+ assert new["ports"][0]["destinationId"] == "b" # new node inherited the successor
296
+ assert [a["id"] for a in f["actions"]] == ["a", "b", "n"]
297
+
298
+
299
+ def test_insert_node_after_a_tail_node_needs_no_successor():
300
+ f = _chain_flow()
301
+ tail = f["actions"][1]
302
+ tail["ports"] = [] # nothing downstream
303
+ ok, msg = nodeparam.insert_node(f, tail, {"id": "n", "actionName": "mid"})
304
+ assert ok and "no successor" in msg
305
+ assert f["actions"][-1]["id"] == "n"
306
+
307
+
308
+ def test_insert_node_refuses_a_branching_anchor():
309
+ """Which branch the new node belongs on is a design decision, not a default."""
310
+ f = _chain_flow()
311
+ a = f["actions"][0]
312
+ a["ports"].append({"id": "p2", "sourceId": "a", "destinationId": "b"})
313
+ ok, msg = nodeparam.insert_node(f, a, {"id": "n"})
314
+ assert ok is False and "outgoing ports" in msg
315
+
316
+
317
+ def test_insert_node_refuses_an_anchor_from_another_flow():
318
+ f = _chain_flow()
319
+ ok, msg = nodeparam.insert_node(f, {"id": "ghost", "actionName": "ghost"}, {"id": "n"})
320
+ assert ok is False and "not in this flow" in msg
321
+
322
+
323
+ def test_to_live_action_lowercases_the_dto_and_its_parameter_rows():
324
+ """The builder emits the CREATE shape; a live flow is camelCase. Splicing one into the
325
+ other unconverted is accepted by the API and renders inconsistently."""
326
+ dto = {"Id": "n", "FlowId": "f", "ActionName": "mid", "CustomData": {"name": "mid"},
327
+ "Parameters": [{"TabPropertyId": "t", "Value": "v", "Variable": []}]}
328
+ live = nodeparam.to_live_action(dto)
329
+ assert set(live) == {"id", "flowId", "actionName", "customData", "parameters"}
330
+ assert live["parameters"][0] == {"tabPropertyId": "t", "value": "v", "variable": []}
331
+ assert live["customData"] == {"name": "mid"}
332
+
333
+
334
+ def test_add_variable_resolves_aliases_and_passes_guids_through():
335
+ f = _typed_flow()
336
+ assert nodeparam.add_variable(f, "a", "string", "process")["dataType"].endswith("121214")
337
+ assert nodeparam.add_variable(f, "b", "file", "input")["dataType"].endswith("121219")
338
+ assert nodeparam.add_variable(f, "c", OBJECT, "output")["dataType"] == OBJECT
339
+
340
+
341
+ def test_defaulting_a_process_variable_needs_no_override():
342
+ """A process variable has no caller and no signature, so stamping its default breaks nobody."""
343
+ f = _typed_flow()
344
+ v = nodeparam.find_variable(f, "exchangeRateList")
345
+ r = nodeparam.set_variable_default(f, v, [1, 2])
346
+ assert r["changed"] is True and r["direction"] == "process"
347
+ assert r["before"] == {"defaultValue": None} and v["defaultValue"] == [1, 2]
348
+
349
+
350
+ def test_defaulting_an_input_needs_the_contract_override():
351
+ """Changing what a run does when the caller supplies nothing is a contract change, even
352
+ though the signature is untouched - so the refusal has to come before the write."""
353
+ f = _typed_flow()
354
+ v = nodeparam.find_variable(f, "payload")
355
+ with pytest.raises(ValueError, match="allow-contract-change"):
356
+ nodeparam.set_variable_default(f, v, {"a": 1})
357
+ assert "defaultValue" not in v
358
+ nodeparam.set_variable_default(f, v, {"a": 1}, allow_contract_change=True)
359
+ assert v["defaultValue"] == {"a": 1}
360
+
361
+
362
+ def test_the_output_direction_is_guarded_too():
363
+ """Both signature-bearing directions are behind the flag, not just the input one."""
364
+ f = _typed_flow()
365
+ with pytest.raises(ValueError, match="is an output variable"):
366
+ nodeparam.set_variable_default(f, nodeparam.find_variable(f, "exchangeRate"), 1.5)
367
+
368
+
369
+ def test_clearing_a_default_is_guarded_as_well_unlike_isrequired():
370
+ """The asymmetry between this and set_variable_required: loosening `isRequired` can never
371
+ break a caller, so it is allowed outright - but REMOVING a default is as much a contract
372
+ change as adding one, because a caller that omitted the field now gets nothing instead of
373
+ the value it silently relied on. The guard is on the DIRECTION, so it fires either way."""
374
+ f = _typed_flow()
375
+ v = nodeparam.find_variable(f, "payload")
376
+ v["defaultValue"] = {"a": 1}
377
+ with pytest.raises(ValueError, match="allow-contract-change"):
378
+ nodeparam.set_variable_default(f, v, None)
379
+ assert v["defaultValue"] == {"a": 1}
380
+ assert nodeparam.set_variable_default(f, v, None, allow_contract_change=True)["changed"] is True
381
+ assert v["defaultValue"] is None
382
+
383
+
384
+ def test_setting_a_default_to_its_current_value_is_a_noop():
385
+ """`changed` drives whether the caller PUTs at all; a false positive is a pointless write."""
386
+ f = _typed_flow()
387
+ v = nodeparam.find_variable(f, "exchangeRateList")
388
+ v["defaultValue"] = [1, 2]
389
+ assert nodeparam.set_variable_default(f, v, [1, 2])["changed"] is False
390
+
391
+
392
+ def test_the_default_is_written_into_the_flow_not_a_copy():
393
+ """The patch is in place: the caller PUTs the flow it passed in, so a write to a detached
394
+ copy would validate, upload, and change nothing."""
395
+ f = _typed_flow()
396
+ nodeparam.set_variable_default(f, nodeparam.find_variable(f, "exchangeRateList"), "x")
397
+ assert [v.get("defaultValue") for v in f["variables"]] == ["x", None, None]
398
+
399
+
400
+ def test_set_variable_default_changes_process_var():
401
+ f = _typed_flow()
402
+ f['variables'][0]['defaultValue'] = 'old-event-id'
403
+ v = nodeparam.find_variable(f, 'exchangeRateList')
404
+ r = nodeparam.set_variable_default(f, v, 'new-event-id')
405
+ assert r['changed'] is True and r['direction'] == 'process'
406
+ assert r['before'] == {'defaultValue': 'old-event-id'}
407
+ assert r['after'] == {'defaultValue': 'new-event-id'}
408
+ assert v['defaultValue'] == 'new-event-id'
409
+
410
+
411
+ def test_set_variable_default_is_a_noop_when_already_that_value():
412
+ f = _typed_flow()
413
+ f['variables'][0]['defaultValue'] = 'same'
414
+ v = nodeparam.find_variable(f, 'exchangeRateList')
415
+ assert nodeparam.set_variable_default(f, v, 'same')['changed'] is False
416
+
417
+
418
+ def test_set_variable_default_allowed_on_input_and_output_vars():
419
+ f = _typed_flow()
420
+ # settable on both directions - but it changes what a run does when the caller says
421
+ # nothing, so unlike a process var it is an EXPLICIT contract change, not a free edit
422
+ for name in ('payload', 'exchangeRate'):
423
+ v = nodeparam.find_variable(f, name)
424
+ r = nodeparam.set_variable_default(f, v, {'k': 1}, allow_contract_change=True)
425
+ assert r['changed'] is True and v['defaultValue'] == {'k': 1}
426
+
427
+
428
+ def test_set_process_title_changes_and_is_noop_when_same():
429
+ f = _typed_flow()
430
+ r = nodeparam.set_process_title(f, 'New Name')
431
+ assert r['changed'] is True and r['before'] == 'T' and f['title'] == 'New Name'
432
+ assert nodeparam.set_process_title(f, 'New Name')['changed'] is False
433
+
434
+
435
+ def test_bind_param_var_turns_literal_token_into_a_bound_placeholder():
436
+ node = {"actionName": "Send Email",
437
+ "parameters": [{"tabPropertyId": "body", "value": "Hey <%firstName%>, welcome", "variable": []}]}
438
+ param = node["parameters"][0]
439
+ r = nodeparam.bind_param_var(node, param, {0: "v-first"}, find="<%firstName%>", replace="<%0%>")
440
+ assert r["value_changed"] is True
441
+ assert param["value"] == "Hey <%0%>, welcome"
442
+ assert param["variable"] == [{"id": 0, "variableId": "v-first", "attribute": None}]
443
+
444
+
445
+ def test_bind_param_var_refuses_mismatched_placeholder_and_binding_sets():
446
+ node = {"actionName": "N", "parameters": [{"tabPropertyId": "body", "value": "Hey <%0%>", "variable": []}]}
447
+ param = node["parameters"][0]
448
+ import pytest as _pt
449
+ with _pt.raises(ValueError, match="each"):
450
+ nodeparam.bind_param_var(node, param, {0: "a", 1: "b"}) # value has only <%0%>
451
+
452
+
453
+ def test_bind_param_var_refuses_a_structured_value():
454
+ node = {"actionName": "N", "parameters": [{"tabPropertyId": "body", "value": {"x": 1}, "variable": []}]}
455
+ import pytest as _pt
456
+ with _pt.raises(ValueError, match="structured"):
457
+ nodeparam.bind_param_var(node, node["parameters"][0], {0: "a"})
458
+
459
+
460
+ def test_handler_variable_set_default_accepts_clear_alone(monkeypatch):
461
+ """Regression on the HANDLER's argument plumbing, which the library tests above never
462
+ reach. `--clear` alone (no --value / --value-file) must clear a process variable's
463
+ default. The guard used to raise 'nothing to set' one line before the --clear branch,
464
+ so --clear was refused by an error that named --clear as the remedy and only worked as
465
+ `--clear --value ""`. The validate/lint/save tail is stubbed so this asserts on the
466
+ plumbing, not the network."""
467
+ from types import SimpleNamespace
468
+ from tools.procesio.handlers import nodeparams
469
+
470
+ flow = {"id": "p1", "title": "T", "actions": [], "variables": [
471
+ {"id": "v", "name": "eventId", "type": 20,
472
+ "dataType": "0317bfee-b2f5-4bde-bfe8-121212121220",
473
+ "isList": False, "defaultValue": "stale"}]}
474
+
475
+ class _Client:
476
+ def get(self, path):
477
+ return flow
478
+
479
+ monkeypatch.setattr(nodeparams, "_validate", lambda c, f: (True, None))
480
+ monkeypatch.setattr(nodeparams, "_lint", lambda c, f: [])
481
+ args = SimpleNamespace(id="p1", variable="eventId", value=None, value_file=None,
482
+ clear=True, json=False, allow_contract_change=False, dry_run=True)
483
+
484
+ res = nodeparams.variable_set_default(_Client(), args) # must not raise
485
+ assert res["variable"] == "eventId"
486
+ assert res["changed"] is True
487
+ assert flow["variables"][0]["defaultValue"] is None # the default was actually cleared
488
+
489
+
490
+ def test_handler_variable_set_default_rejects_clear_with_a_value():
491
+ """The other half of the fix: --clear combined with --value hides which one wins, so it
492
+ is refused up front rather than silently letting one shadow the other."""
493
+ from types import SimpleNamespace
494
+ from tools.procesio.handlers import nodeparams
495
+ from tools.procesio.errors import UsageError
496
+
497
+ flow = {"id": "p1", "title": "T", "actions": [], "variables": [
498
+ {"id": "v", "name": "eventId", "type": 20, "defaultValue": "stale"}]}
499
+
500
+ class _Client:
501
+ def get(self, path):
502
+ return flow
503
+
504
+ args = SimpleNamespace(id="p1", variable="eventId", value="x", value_file=None,
505
+ clear=True, json=False, allow_contract_change=False, dry_run=True)
506
+ with pytest.raises(UsageError, match="do not combine it with"):
507
+ nodeparams.variable_set_default(_Client(), args)
508
+
509
+
510
+
511
+ # --------------------------------------------------------------------------- error ports
512
+
513
+ def _err_flow():
514
+ """Two nodes in a line: a Call API that can fault, and the Node that consumes its response.
515
+
516
+ Shaped like the live DTO on the detail that matters here - ports live on the SOURCE action and
517
+ carry `destinationId` - because an error port written on the wrong side validates and never
518
+ fires.
519
+ """
520
+ return {
521
+ "id": "flow-e", "title": "Bootstrap",
522
+ "variables": [{"id": "var-res", "name": "response", "type": 20}],
523
+ "actions": [
524
+ {"id": "call-1", "actionName": "List the workspace credentials",
525
+ "actionTemplateName": "Call API", "variableErrorId": None,
526
+ "parameters": [], "customData": {},
527
+ "ports": [{"id": "p1", "flowId": "flow-e", "sourceId": "call-1",
528
+ "destinationId": "node-1", "type": 0, "state": 1, "data": {}}]},
529
+ {"id": "node-1", "actionName": "Keep only the calendar ones",
530
+ "actionTemplateName": "Node", "parameters": [], "customData": {}, "ports": []},
531
+ {"id": "join-1", "actionName": "Join", "actionTemplateName": "Join",
532
+ "parameters": [], "customData": {}, "ports": []},
533
+ ],
534
+ }
535
+
536
+
537
+ def test_an_error_port_is_written_as_all_three_parts():
538
+ flow = _err_flow()
539
+ node = nodeparam.find_node(flow, "List the workspace credentials")
540
+ handler = nodeparam.find_node(flow, "Keep only the calendar ones")
541
+ report = nodeparam.set_error_port(flow, node, handler)
542
+
543
+ err = [p for p in node["ports"] if p["type"] == 1]
544
+ assert len(err) == 1
545
+ assert err[0]["destinationId"] == "node-1"
546
+ assert err[0]["data"] == {"isDefault": "error"} # the port
547
+ var = next(v for v in flow["variables"] if v["id"] == node["variableErrorId"])
548
+ assert var["isError"] is True # the variable
549
+ assert var["dataType"] == nodeparam.ERROR_DATA_MODEL # of the only accepted datatype
550
+ assert report["handler"] == "Keep only the calendar ones"
551
+ assert report["variable_created"] is True
552
+
553
+
554
+ def test_the_normal_port_is_left_alone():
555
+ flow = _err_flow()
556
+ node = nodeparam.find_node(flow, "List the workspace credentials")
557
+ nodeparam.set_error_port(flow, node, nodeparam.find_node(flow, "Keep only the calendar ones"))
558
+ normal = [p for p in node["ports"] if p["type"] == 0]
559
+ assert len(normal) == 1 and normal[0]["id"] == "p1" and normal[0]["destinationId"] == "node-1"
560
+
561
+
562
+ def test_rewiring_replaces_the_port_rather_than_adding_a_second():
563
+ flow = _err_flow()
564
+ node = nodeparam.find_node(flow, "List the workspace credentials")
565
+ nodeparam.set_error_port(flow, node, nodeparam.find_node(flow, "Keep only the calendar ones"))
566
+ first_var = node["variableErrorId"]
567
+ report = nodeparam.set_error_port(flow, node, nodeparam.find_node(flow, "Join"))
568
+ assert len([p for p in node["ports"] if p["type"] == 1]) == 1
569
+ assert report["handler_before"] == "node-1"
570
+ assert node["variableErrorId"] == first_var # the variable is reused, not duplicated
571
+ assert len([v for v in flow["variables"] if v.get("isError")]) == 1
572
+
573
+
574
+ def test_a_half_wired_error_variable_is_repaired_not_trusted():
575
+ """A plain string variable in that slot validates and the port never fires, so the shape is
576
+ corrected on the way past rather than left as the caller found it."""
577
+ flow = _err_flow()
578
+ flow["variables"].append({"id": "var-bad", "name": "oops", "type": 20,
579
+ "dataType": "0317bfee-b2f5-4bde-bfe8-121212121214", "isError": False})
580
+ node = nodeparam.find_node(flow, "List the workspace credentials")
581
+ node["variableErrorId"] = "var-bad"
582
+ nodeparam.set_error_port(flow, node, nodeparam.find_node(flow, "Keep only the calendar ones"))
583
+ var = next(v for v in flow["variables"] if v["id"] == "var-bad")
584
+ assert var["isError"] is True and var["dataType"] == nodeparam.ERROR_DATA_MODEL
585
+
586
+
587
+ def test_clear_removes_the_port_and_its_now_unused_variable():
588
+ flow = _err_flow()
589
+ node = nodeparam.find_node(flow, "List the workspace credentials")
590
+ nodeparam.set_error_port(flow, node, nodeparam.find_node(flow, "Keep only the calendar ones"))
591
+ report = nodeparam.set_error_port(flow, node, None, clear=True)
592
+ assert [p for p in node["ports"] if p["type"] == 1] == []
593
+ assert node["variableErrorId"] is None
594
+ assert [v for v in flow["variables"] if v.get("isError")] == []
595
+ assert report["cleared"] is True and report["handler_before"] == "node-1"
596
+
597
+
598
+ def test_a_template_without_an_error_port_is_refused():
599
+ flow = _err_flow()
600
+ with pytest.raises(ValueError) as e:
601
+ nodeparam.set_error_port(flow, nodeparam.find_node(flow, "Join"),
602
+ nodeparam.find_node(flow, "Keep only the calendar ones"))
603
+ assert "no error port" in str(e.value)
604
+
605
+
606
+ def test_a_node_cannot_handle_its_own_error():
607
+ flow = _err_flow()
608
+ node = nodeparam.find_node(flow, "List the workspace credentials")
609
+ with pytest.raises(ValueError) as e:
610
+ nodeparam.set_error_port(flow, node, node)
611
+ assert "its own error" in str(e.value)
612
+
613
+
614
+ def test_a_handler_outside_the_flow_is_refused():
615
+ flow = _err_flow()
616
+ node = nodeparam.find_node(flow, "List the workspace credentials")
617
+ with pytest.raises(ValueError) as e:
618
+ nodeparam.set_error_port(flow, node, {"id": "elsewhere", "actionName": "Other"})
619
+ assert "not in this flow" in str(e.value)
620
+
621
+
622
+ # --------------------------------------------------------------------------- Query Store nodes
623
+
624
+ def _qs_node(statement="SELECT <%0%>\nFROM <%1%>", chips=None, pmap=None):
625
+ return {"id": "qs-1", "actionName": "Read the meetings 1",
626
+ "actionTemplateName": "Query Store", "customData": {}, "ports": [],
627
+ "parameters": [
628
+ {"tabPropertyId": "02577ada-0000-0200-0000-00000000b102", "value": statement,
629
+ "variable": chips if chips is not None else [{"id": 0}, {"id": 1}]},
630
+ {"tabPropertyId": "02577ada-0000-0200-0000-00000000b103", "value": pmap or [],
631
+ "variable": []},
632
+ {"tabPropertyId": "02577ada-0000-0200-0000-00000000b104", "value": "1800",
633
+ "variable": []},
634
+ ]}
635
+
636
+
637
+ def test_the_statement_and_its_params_map_are_found_by_property_suffix():
638
+ node = _qs_node()
639
+ query, pmap = nodeparam.find_query_params(node)
640
+ assert query["value"].startswith("SELECT")
641
+ assert pmap["value"] == []
642
+
643
+
644
+ def test_a_node_with_no_statement_reports_none():
645
+ node = {"id": "n", "actionName": "Some node", "actionTemplateName": "Node",
646
+ "parameters": [{"tabPropertyId": "whatever-else", "value": "x"}]}
647
+ assert nodeparam.find_query_params(node) == (None, None)
648
+
649
+
650
+ def test_a_non_empty_params_map_is_visible_to_the_caller():
651
+ """The guard that protects a bound @param lives in the handler, so the model has to hand the
652
+ map back rather than hide it."""
653
+ node = _qs_node(pmap=[{"id": 0, "source": {"value": "<%7%>"},
654
+ "destination": {"value": "e", "variable": []}}])
655
+ _, pmap = nodeparam.find_query_params(node)
656
+ assert pmap["value"] and pmap["value"][0]["destination"]["value"] == "e"
657
+
658
+
659
+ def _qs_full():
660
+ """A Query Store node shaped like the live release step: statement chips 0-4, a parameters map
661
+ on 5-7, and an output binding on 8 - one sequence across three parameters."""
662
+ return {"id": "qs", "actionName": "Update the meetings 3", "actionTemplateName": "Query Store",
663
+ "customData": {}, "ports": [], "parameters": [
664
+ {"tabPropertyId": "x-b102",
665
+ "value": "UPDATE <%0%>\nSET <%1%> = 'Cancelled', <%2%> = NULL\n"
666
+ "WHERE <%3%> = @mid\nAND <%4%> = 'Confirmed'",
667
+ "variable": [{"id": i} for i in range(5)]},
668
+ {"tabPropertyId": "x-b103", "value": [
669
+ {"id": 0, "source": {"value": "<%5%>", "variable": [{"id": 5, "variableId": "v-row"}]},
670
+ "destination": {"value": "mid", "variable": []}},
671
+ {"id": 1, "source": {"value": "<%6%>", "variable": [{"id": 6, "variableId": "v-st"}]},
672
+ "destination": {"value": "status", "variable": []}},
673
+ ], "variable": []},
674
+ {"tabPropertyId": "x-b104", "value": "1800", "variable": []},
675
+ {"tabPropertyId": "x-b106", "value": "<%7%>",
676
+ "variable": [{"id": 7, "variableId": "v-out"}]},
677
+ ]}
678
+
679
+
680
+ def test_renumbering_keeps_one_sequence_across_every_parameter():
681
+ node = _qs_full()
682
+ query, pmap = nodeparam.find_query_params(node)
683
+ nxt = nodeparam.renumber_node_placeholders(node, [query, pmap])
684
+ assert nxt == 8
685
+ assert node["parameters"][0]["value"].startswith("UPDATE <%0%>")
686
+ rows = node["parameters"][1]["value"]
687
+ assert [r["source"]["value"] for r in rows] == ["<%5%>", "<%6%>"]
688
+ assert node["parameters"][3]["value"] == "<%7%>" # the output keeps its place at the end
689
+
690
+
691
+ def test_growing_the_map_pushes_the_output_binding_along():
692
+ """The failure this exists to stop: two more map rows and the output index moves, so an output
693
+ left at its old number is written back to the wrong variable."""
694
+ node = _qs_full()
695
+ query, pmap = nodeparam.find_query_params(node)
696
+ pmap["value"].append({"id": 2, "source": {"value": "<%99%>",
697
+ "variable": [{"id": 99, "variableId": "v-new"}]},
698
+ "destination": {"value": "event", "variable": []}})
699
+ nodeparam.renumber_node_placeholders(node, [query, pmap])
700
+ rows = node["parameters"][1]["value"]
701
+ assert [r["source"]["value"] for r in rows] == ["<%5%>", "<%6%>", "<%7%>"]
702
+ assert [r["source"]["variable"][0]["id"] for r in rows] == [5, 6, 7]
703
+ out = node["parameters"][3]
704
+ assert out["value"] == "<%8%>" and out["variable"][0]["id"] == 8
705
+
706
+
707
+ def test_binding_ids_and_their_value_stay_in_step():
708
+ node = _qs_full()
709
+ query, pmap = nodeparam.find_query_params(node)
710
+ nodeparam.renumber_node_placeholders(node, [query, pmap])
711
+ for p in node["parameters"]:
712
+ for b in p.get("variable") or []:
713
+ if isinstance(b.get("id"), int) and isinstance(p.get("value"), str):
714
+ assert ("<%%%d%%>" % b["id"]) in p["value"] or p["tabPropertyId"].endswith("b102")
715
+
716
+
717
+ # --------------------------------------------------------------------------- structured bindings
718
+
719
+ def _body_node():
720
+ """A Call API node whose Request Parameters is a dict holding a JSON template - the shape that
721
+ bind_param_var refuses and that an HTTP body always has."""
722
+ return {"id": "api-1", "actionName": "Create the calendar event",
723
+ "actionTemplateName": "Call API", "customData": {}, "ports": [],
724
+ "parameters": [{
725
+ "tabPropertyId": "x-0003",
726
+ "value": {"body": {"type": "RAW", "value": {"RAW": {
727
+ "format": "json",
728
+ "value": '{\n "summary": "<%4%>",\n "start": {\n "dateTime": "<%8%>"\n }\n}'}}},
729
+ "headers": [], "queryParams": []},
730
+ "variable": [{"id": 4, "variableId": "v-row",
731
+ "attribute": {"attributeId": "a-name", "nextAttribute": None}},
732
+ {"id": 8, "variableId": "v-row",
733
+ "attribute": {"attributeId": "a-start", "nextAttribute": None}}],
734
+ }]}
735
+
736
+
737
+ def test_a_binding_can_be_added_inside_a_structured_parameter():
738
+ node = _body_node()
739
+ p = node["parameters"][0]
740
+ report = nodeparam.add_param_bindings(
741
+ node, p, {12: {"variableId": "v-row", "attributeId": "a-zone"}},
742
+ find='"dateTime": "<%8%>"',
743
+ replace='"dateTime": "<%8%>",\n "timeZone": "<%12%>"')
744
+ raw = p["value"]["body"]["value"]["RAW"]["value"]
745
+ assert '"timeZone": "<%12%>"' in raw
746
+ assert report["replacements"] == 1 and report["bindings_total"] == 3
747
+ new = next(b for b in p["variable"] if b["id"] == 12)
748
+ assert new["attribute"] == {"attributeId": "a-zone", "nextAttribute": None}
749
+
750
+
751
+ def test_the_existing_bindings_are_kept_with_their_attribute_paths():
752
+ node = _body_node()
753
+ p = node["parameters"][0]
754
+ nodeparam.add_param_bindings(node, p, {12: {"variableId": "v-row", "attributeId": "a-zone"}},
755
+ find='"dateTime": "<%8%>"',
756
+ replace='"dateTime": "<%8%>",\n "timeZone": "<%12%>"')
757
+ by_id = {b["id"]: b for b in p["variable"]}
758
+ assert by_id[4]["attribute"]["attributeId"] == "a-name"
759
+ assert by_id[8]["attribute"]["attributeId"] == "a-start"
760
+
761
+
762
+ def test_a_placeholder_left_unbound_is_refused():
763
+ node = _body_node()
764
+ p = node["parameters"][0]
765
+ with pytest.raises(ValueError) as e:
766
+ nodeparam.add_param_bindings(node, p, {}, find='"<%8%>"',
767
+ replace='"<%8%>", "timeZone": "<%12%>"')
768
+ assert "exactly one binding" in str(e.value)
769
+
770
+
771
+ def test_a_binding_with_no_placeholder_is_refused():
772
+ node = _body_node()
773
+ p = node["parameters"][0]
774
+ with pytest.raises(ValueError) as e:
775
+ nodeparam.add_param_bindings(node, p, {99: {"variableId": "v-row", "attributeId": "a-x"}})
776
+ assert "exactly one binding" in str(e.value)
777
+
778
+
779
+ def test_a_binding_with_no_attribute_is_written_as_the_whole_variable():
780
+ node = _body_node()
781
+ p = node["parameters"][0]
782
+ nodeparam.add_param_bindings(node, p, {12: {"variableId": "v-other"}},
783
+ find='"dateTime": "<%8%>"',
784
+ replace='"dateTime": "<%8%>",\n "tz": "<%12%>"')
785
+ assert next(b for b in p["variable"] if b["id"] == 12)["attribute"] is None
786
+
787
+
788
+ def test_find_text_that_is_absent_is_refused():
789
+ node = _body_node()
790
+ p = node["parameters"][0]
791
+ with pytest.raises(ValueError) as e:
792
+ nodeparam.add_param_bindings(node, p, {}, find="nothing like this", replace="x")
793
+ assert "not present" in str(e.value)
794
+
795
+
796
+ def _engine_owned_flow():
797
+ return {"id": "f", "title": "T", "actions": [], "variables": [
798
+ {"id": "v-sys", "name": "processInfo", "type": 40,
799
+ "dataType": "0317bfee-b2f5-4bde-bfe8-121212121220", "isList": False},
800
+ {"id": "v-auto", "name": "Call_Subprocess_ChildInstanceId", "type": 50,
801
+ "dataType": "0317bfee-b2f5-4bde-bfe8-121212121222", "isList": False,
802
+ "defaultValue": None},
803
+ ]}
804
+
805
+
806
+ @pytest.mark.parametrize("name", ["processInfo", "Call_Subprocess_ChildInstanceId"])
807
+ def test_an_engine_owned_variable_cannot_be_retyped_even_with_the_override(name):
808
+ f = _engine_owned_flow()
809
+ v = nodeparam.find_variable(f, name)
810
+ with pytest.raises(ValueError, match="the engine writes it"):
811
+ nodeparam.set_variable_type(f, v, OBJECT, allow_contract_change=True)
812
+ assert v["dataType"] != OBJECT
813
+
814
+
815
+ @pytest.mark.parametrize("name", ["processInfo", "Call_Subprocess_ChildInstanceId"])
816
+ def test_an_engine_owned_variable_cannot_be_given_a_default(name):
817
+ f = _engine_owned_flow()
818
+ v = nodeparam.find_variable(f, name)
819
+ before = v.get("defaultValue")
820
+ with pytest.raises(ValueError, match="the engine writes it"):
821
+ nodeparam.set_variable_default(f, v, "x", allow_contract_change=True)
822
+ assert v.get("defaultValue") == before
823
+
824
+
825
+ def test_auto_is_a_known_direction():
826
+ assert nodeparam.VAR_DIRECTION[50] == "auto"