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,336 @@
1
+ """Rewrite the ORDERED event chains of several elements on a live form, in one save.
2
+
3
+ `form-set-element-event` appends or swaps ONE event of ONE action type. A behaviour change on a
4
+ multi-step form is rarely that small: a button's chain is an ordered mix of RUN_JAVASCRIPT,
5
+ RUN_PROCESS and MAP_FORM_DATA blocks, and the ORDER is the behaviour. Moving a MAP, adding a
6
+ condition to it or spreading one decision across several elements means restating whole chains,
7
+ and on a form with hundreds of hand-built elements that must still be surgical and atomic, not
8
+ a desired-state rebuild.
9
+
10
+ A PLAN lists, for each (element, trigger), the new chain in order:
11
+
12
+ {"chains": [{"element": "<name or id>", "on": "click",
13
+ "events": [{"keep": "<existing event id>"},
14
+ {"map": {"set": {"Input2.disabled": true, "@isPF": true},
15
+ "when": [{"field": "flag.value", "op": "EQUALS", "value": "1"},
16
+ {"variable": "isPF", "op": "IS_TRUE"}],
17
+ "match": "all"}},
18
+ {"js": "<code>"} | {"js_file": "<path>"},
19
+ {"raw": {<a complete event>}}]}]}
20
+
21
+ * `keep` re-uses an existing event of that element and trigger VERBATIM, id included, so a large
22
+ script is never re-sent or re-typed.
23
+ * A `map` target is `<element>.<configKey>` (resolved to {root}.{FIELDS_NS}.{elementId}.{configId})
24
+ or `@<formVariable>` (the variable id). A condition operand is `field` (`<element>` for its value,
25
+ `<element>.<configKey>` for any other config) or `variable`. `match` is `all` (AND) or `any` (OR).
26
+ * Every name, config key, variable, operator and kept id is resolved BEFORE anything is written.
27
+ A wrong path is otherwise saved without an error and the block silently does nothing.
28
+ * Events not listed in a chain are dropped, and the result names them.
29
+ * All chains land in ONE GET -> PUT behind the concurrency guard.
30
+
31
+ Wire shapes were copied from MAP_FORM_DATA blocks the designer itself wrote (verified on a live
32
+ form): an unconditional block's config is `{"mapping": [...]}`, while a conditional one adds
33
+ `conditions` + `areConditionsConfigured: true`. A condition's `logicOperator` links it to the NEXT
34
+ condition (1 = AND, 2 = OR, 0 on the last). `operandsAsListOptional` follows the operator (see
35
+ _LIST_OPTIONAL_OPS). Mapping values are strings: booleans become "true"/"false".
36
+ """
37
+ from __future__ import annotations
38
+
39
+ import argparse
40
+ import copy
41
+ import json
42
+ import os
43
+ import uuid
44
+
45
+ from tools.procesio import formlint
46
+ from tools.procesio.actiondef import ActionDef
47
+ from tools.procesio.dto.form import fieldpath
48
+ from tools.procesio.errors import UsageError
49
+ from tools.procesio.handlers.common import add_force_arg, add_profile_arg, guard_unchanged
50
+ from tools.procesio.handlers.form_code import _fetch, build_put_body
51
+ from tools.procesio.handlers.form_events import _cfg, _find_element, _resolve_trigger
52
+
53
+ # Every operator seen in real form/process conditions (counted across exported workspaces).
54
+ OPERATORS = (
55
+ "EQUALS", "DOES_NOT_EQUAL", "CONTAINS", "DOES_NOT_CONTAIN", "IS_EMPTY", "IS_NOT_EMPTY",
56
+ "IS_TRUE", "IS_FALSE", "GREATER_THAN", "GREATER_THAN_OR_EQUAL_TO", "LESS_THAN",
57
+ "LESS_THAN_OR_EQUAL_TO", "BELONGS", "DOES_NOT_BELONG",
58
+ )
59
+ _LOGIC = {"all": 1, "and": 1, "any": 2, "or": 2}
60
+ # The designer sets `operandsAsListOptional` by OPERATOR, not by operand kind: counted over every
61
+ # condition of a large production form, it is true for exactly these four and false for
62
+ # CONTAINS / DOES_NOT_CONTAIN / IS_TRUE / IS_FALSE, on fields and variables alike.
63
+ _LIST_OPTIONAL_OPS = {"EQUALS", "DOES_NOT_EQUAL", "IS_EMPTY", "IS_NOT_EMPTY"}
64
+
65
+
66
+ def _operand(value) -> dict:
67
+ return {"variable": "", "attribute": {"id": "", "nextAttribute": None}, "value": value}
68
+
69
+
70
+ def _as_string(value) -> str:
71
+ if value is True:
72
+ return "true"
73
+ if value is False:
74
+ return "false"
75
+ if value is None:
76
+ return ""
77
+ return str(value)
78
+
79
+
80
+ class _Resolver:
81
+ """Names -> ids for one live form: element configs and form variables."""
82
+
83
+ def __init__(self, form: dict):
84
+ self.live = fieldpath.LiveForm(form)
85
+ data = form.get("data") or {}
86
+ self.variables = {v.get("name"): v.get("id") for v in data.get("variables") or []
87
+ if v.get("name") and v.get("id")}
88
+
89
+ def variable(self, name: str, where: str) -> str:
90
+ vid = self.variables.get(name)
91
+ if not vid:
92
+ raise UsageError(f"{where}: {name!r} is not a form variable; known: "
93
+ f"{', '.join(sorted(self.variables)) or '(none)'}")
94
+ return vid
95
+
96
+ def target(self, ref: str, where: str) -> str:
97
+ """`@var` -> variable id; `<element>.<key>` -> config path (split on the LAST dot, so an
98
+ element name may itself contain dots)."""
99
+ ref = str(ref).strip()
100
+ if ref.startswith("@"):
101
+ return self.variable(ref[1:], where)
102
+ if "." not in ref:
103
+ raise UsageError(f"{where}: {ref!r} must be '<element>.<configKey>' or '@<variable>'")
104
+ el, key = ref.rsplit(".", 1)
105
+ try:
106
+ return self.live.config_path(el, key)
107
+ except UsageError as e:
108
+ raise UsageError(f"{where}: {e}") from e
109
+
110
+ def field(self, ref: str, where: str) -> str:
111
+ """A condition's field operand: `<element>` means its value, `<element>.<key>` any config."""
112
+ ref = str(ref).strip()
113
+ try:
114
+ if ref in self.live.by_name or ref in self.live.by_id:
115
+ el = self.live.element(ref)
116
+ return self.live.config_path(ref, fieldpath.value_key(el.get("type")))
117
+ el, key = ref.rsplit(".", 1) if "." in ref else (ref, "value")
118
+ return self.live.config_path(el, key)
119
+ except UsageError as e:
120
+ raise UsageError(f"{where}: {e}") from e
121
+
122
+
123
+ def _conditions(when: list, match: str, res: _Resolver, where: str) -> list:
124
+ logic = _LOGIC.get(str(match or "all").lower())
125
+ if logic is None:
126
+ raise UsageError(f"{where}: match must be 'all' or 'any', not {match!r}")
127
+ out = []
128
+ for i, c in enumerate(when):
129
+ if not isinstance(c, dict):
130
+ raise UsageError(f"{where}: condition {i} must be an object")
131
+ op = str(c.get("op") or "").strip().upper()
132
+ if op not in OPERATORS:
133
+ raise UsageError(f"{where}: condition {i} op {c.get('op')!r} is not one of "
134
+ f"{', '.join(OPERATORS)}")
135
+ if "variable" in c:
136
+ left = res.variable(c["variable"], f"{where} condition {i}")
137
+ elif "field" in c:
138
+ left = res.field(c["field"], f"{where} condition {i}")
139
+ else:
140
+ raise UsageError(f"{where}: condition {i} needs 'field' or 'variable'")
141
+ out.append({
142
+ "id": i, "uid": str(uuid.uuid4()), "operator": op,
143
+ "leftOperator": _operand(left),
144
+ "rightOperator": _operand(_as_string(c.get("value", ""))),
145
+ "auxOperator": _operand(""),
146
+ "logicOperator": logic if i < len(when) - 1 else 0,
147
+ "value": None,
148
+ "rightOperandAsListRequired": False,
149
+ "operandsAsListOptional": op in _LIST_OPTIONAL_OPS,
150
+ })
151
+ return out
152
+
153
+
154
+ def _map_event(spec: dict, event_type: str, res: _Resolver, where: str) -> dict:
155
+ sets = spec.get("set")
156
+ if not isinstance(sets, dict) or not sets:
157
+ raise UsageError(f"{where}: a map needs a non-empty 'set' object")
158
+ mapping = [{"id": i, "left": res.target(k, f"{where} set {k!r}"), "right": _as_string(v)}
159
+ for i, (k, v) in enumerate(sets.items())]
160
+ config: dict = {"mapping": mapping}
161
+ when = spec.get("when") or []
162
+ if when:
163
+ config["conditions"] = _conditions(when, spec.get("match", "all"), res, where)
164
+ config["areConditionsConfigured"] = True
165
+ return {"id": str(uuid.uuid4()), "type": event_type, "action": "MAP_FORM_DATA",
166
+ "config": config}
167
+
168
+
169
+ def _js_event(code: str, event_type: str, where: str) -> dict:
170
+ if not isinstance(code, str) or not code.strip():
171
+ raise UsageError(f"{where}: empty JavaScript")
172
+ return {"id": str(uuid.uuid4()), "type": event_type, "action": "RUN_JAVASCRIPT",
173
+ "config": {"code": code}}
174
+
175
+
176
+ def _summary(ev: dict, live: fieldpath.LiveForm, variables: dict) -> dict:
177
+ """A human-readable line per event, so a dry run can be reviewed without reading guids."""
178
+ ids_to_var = {v: k for k, v in variables.items()}
179
+ by_cfg = {}
180
+ for el in live.elements:
181
+ name = fieldpath._name_of(el) or el.get("id")
182
+ for c in el.get("configs") or []:
183
+ by_cfg[(str(el.get("id")), str(c.get("id")))] = f"{name}.{c.get('key')}"
184
+
185
+ def name_of(path):
186
+ if path in ids_to_var:
187
+ return "@" + ids_to_var[path]
188
+ parts = str(path).split(".")
189
+ if len(parts) == fieldpath.SEGMENTS:
190
+ return by_cfg.get((parts[2], parts[3]), path)
191
+ return path
192
+
193
+ out = {"id": ev.get("id"), "action": ev.get("action")}
194
+ cfg = ev.get("config") or {}
195
+ if ev.get("action") == "MAP_FORM_DATA":
196
+ out["set"] = {name_of(m.get("left")): m.get("right") for m in cfg.get("mapping") or []}
197
+ conds = cfg.get("conditions") or []
198
+ if conds:
199
+ out["when"] = [f"{name_of(c['leftOperator'].get('value'))} {c.get('operator')} "
200
+ f"{c['rightOperator'].get('value')!r}" for c in conds]
201
+ elif ev.get("action") == "RUN_JAVASCRIPT":
202
+ code = cfg.get("code") or ""
203
+ out["js"] = f"{len(code)} chars: " + code.strip().splitlines()[0][:90] if code.strip() else ""
204
+ elif ev.get("action") == "RUN_PROCESS":
205
+ out["processId"] = cfg.get("processId")
206
+ return out
207
+
208
+
209
+ def _load_plan(args) -> dict:
210
+ raw = args.plan
211
+ base = os.getcwd()
212
+ if args.plan_file:
213
+ with open(args.plan_file, encoding="utf-8") as f:
214
+ raw = f.read()
215
+ base = os.path.dirname(os.path.abspath(args.plan_file))
216
+ if not raw:
217
+ raise UsageError("provide --plan '<json>' or --plan-file <path>")
218
+ try:
219
+ plan = json.loads(raw)
220
+ except json.JSONDecodeError as e:
221
+ raise UsageError(f"the plan must be valid JSON: {e}") from e
222
+ if not isinstance(plan, dict) or not isinstance(plan.get("chains"), list) or not plan["chains"]:
223
+ raise UsageError("the plan must be an object with a non-empty 'chains' list")
224
+ plan["_base"] = base
225
+ return plan
226
+
227
+
228
+ def set_element_chains(client, args) -> dict:
229
+ plan = _load_plan(args)
230
+ form = _fetch(client, args.id)
231
+ data = form["data"]
232
+ elements = data.get("elements") or []
233
+ count_before = len(elements)
234
+ res = _Resolver(form)
235
+
236
+ staged, report, seen, warnings = [], [], set(), []
237
+ for n, chain in enumerate(plan["chains"]):
238
+ where = f"chains[{n}]"
239
+ if not isinstance(chain, dict) or not chain.get("element") or not chain.get("on"):
240
+ raise UsageError(f"{where}: needs 'element' and 'on'")
241
+ element = _find_element(elements, str(chain["element"]))
242
+ cfg_key, event_type = _resolve_trigger(str(chain["on"]))
243
+ if (element.get("id"), cfg_key) in seen:
244
+ raise UsageError(f"{where}: {chain['element']!r} {cfg_key} appears twice in the plan")
245
+ seen.add((element.get("id"), cfg_key))
246
+ slot = _cfg(element, cfg_key)
247
+ if slot is None:
248
+ raise UsageError(f"{where}: element {chain['element']!r} has no {cfg_key!r} config")
249
+ current = slot.get("value") or {}
250
+ previous = list(current.get("events") or [])
251
+ by_id = {e.get("id"): e for e in previous}
252
+
253
+ new_events, kept = [], []
254
+ for i, spec in enumerate(chain.get("events") or []):
255
+ w = f"{where}.events[{i}] ({chain['element']})"
256
+ if not isinstance(spec, dict) or len(spec) != 1:
257
+ raise UsageError(f"{w}: each event is one of keep / map / js / js_file / raw")
258
+ kind, body = next(iter(spec.items()))
259
+ if kind == "keep":
260
+ if body not in by_id:
261
+ raise UsageError(f"{w}: no event {body!r} on this element's {cfg_key}; it has "
262
+ f"{', '.join(str(k) for k in by_id) or '(none)'}")
263
+ if body in kept:
264
+ raise UsageError(f"{w}: event {body!r} is kept twice")
265
+ kept.append(body)
266
+ new_events.append(copy.deepcopy(by_id[body]))
267
+ elif kind == "map":
268
+ new_events.append(_map_event(body, event_type, res, w))
269
+ elif kind == "js":
270
+ new_events.append(_js_event(body, event_type, w))
271
+ elif kind == "js_file":
272
+ path = body if os.path.isabs(body) else os.path.join(plan["_base"], body)
273
+ with open(path, encoding="utf-8") as f:
274
+ new_events.append(_js_event(f.read(), event_type, w))
275
+ elif kind == "raw":
276
+ if not isinstance(body, dict) or not body.get("action"):
277
+ raise UsageError(f"{w}: raw needs a complete event object")
278
+ ev = copy.deepcopy(body)
279
+ ev.setdefault("id", str(uuid.uuid4()))
280
+ ev.setdefault("type", event_type)
281
+ new_events.append(ev)
282
+ else:
283
+ raise UsageError(f"{w}: unknown event kind {kind!r}")
284
+
285
+ staged.append((slot, {"debounce": current.get("debounce", 0), "events": new_events}))
286
+ warnings += formlint.string_boolean_conditions(
287
+ new_events, data.get("variables"), f"{chain['element']} {cfg_key}")
288
+ report.append({
289
+ "element": chain["element"], "elementId": element.get("id"), "trigger": cfg_key,
290
+ "previous": [_summary(e, res.live, res.variables) for e in previous],
291
+ "events": [_summary(e, res.live, res.variables) for e in new_events],
292
+ "kept": kept,
293
+ "dropped": [e.get("id") for e in previous if e.get("id") not in kept],
294
+ })
295
+
296
+ result = {"id": args.id, "chains": report, "elements": count_before}
297
+ if warnings:
298
+ result["warnings"] = warnings
299
+ if args.dry_run:
300
+ return {"dry_run": True, **result}
301
+
302
+ guard = guard_unchanged(lambda: _fetch(client, args.id), form, force=args.force)
303
+ for slot, value in staged:
304
+ slot["value"] = value
305
+ if len(data.get("elements") or []) != count_before:
306
+ raise UsageError("element count changed while staging; refusing to PUT")
307
+ client.put("/api/FormTemplate", build_put_body(form, data=data))
308
+ return {"updated": True, "concurrency": guard, **result}
309
+
310
+
311
+ def _args(p: argparse.ArgumentParser) -> None:
312
+ add_profile_arg(p)
313
+ p.add_argument("--id", required=True, help="form template id")
314
+ p.add_argument("--plan", help="the chains plan as JSON (see the action description)")
315
+ p.add_argument("--plan-file", dest="plan_file",
316
+ help="path to the plan JSON; js_file paths inside it resolve relative to it")
317
+ p.add_argument("--dry-run", dest="dry_run", action="store_true",
318
+ help="resolve and report every chain (names, not guids) without saving")
319
+ add_force_arg(p)
320
+
321
+
322
+ ACTIONS = {
323
+ "form-set-element-chains": ActionDef(
324
+ func=set_element_chains, add_args=_args, needs_client=True,
325
+ description="Rewrite the ORDERED event chains of one or more elements on a live form in "
326
+ "ONE save (surgical: only the listed element triggers change). Each chain "
327
+ "lists its events in order: {keep: <existing event id>} re-uses an event "
328
+ "verbatim (large scripts are never re-sent), {map: {set: {'<element>."
329
+ "<configKey>': value, '@<variable>': value}, when: [{field|variable, op, "
330
+ "value}], match: all|any}} builds a MAP_FORM_DATA block from NAMES, {js: "
331
+ "code} / {js_file: path} adds a RUN_JAVASCRIPT block, {raw: event} passes an "
332
+ "event through. Every name, config key, variable, operator and kept id is "
333
+ "resolved before writing; events not listed are dropped and reported. "
334
+ "--dry-run prints each chain by name.",
335
+ ),
336
+ }
@@ -0,0 +1,277 @@
1
+ """Surgical read/write of a form's global CSS + JavaScript (`Data.code`).
2
+
3
+ Why this exists as its own pair of actions rather than going through `form-edit`:
4
+ `form-edit` is a DESIRED-STATE editor — it rebuilds the whole DTO from a config, so
5
+ using it to change one field on a large hand-authored form means re-declaring every
6
+ element or losing them. Restyling an existing form is the common case, so these two
7
+ actions do a read-modify-write on the LIVE DTO and touch ONLY `Data.code`, leaving
8
+ the element tree, theme, data model and events byte-identical.
9
+
10
+ `Data.code` is the designer's "Switch to code" editor and is stored AES-encrypted
11
+ (see dto/form/code_cipher.py + FORM-STYLING-NOTES.md); there is no plaintext field
12
+ on the DTO, so both directions need the `form-code-key` secret. The CSS is injected
13
+ by the renderer as a `<style>` prepended inside the form root; the JS is replayed as
14
+ a synthetic RUN_JAVASCRIPT event on mount and on every change, so it must be
15
+ idempotent — it runs more than once per page.
16
+
17
+ `form-set-code` always returns the PREVIOUS decrypted css/js under `previous`, so an
18
+ overwrite is recoverable from the tool output alone.
19
+
20
+ Concurrency (applies to EVERY surgical form/process action): each is a read-modify-write
21
+ of the WHOLE live DTO via PUT — there is no version/ETag check, so it is last-write-wins.
22
+ Two surgical writes racing each other, or one racing a designer "Save", silently clobber
23
+ whichever landed first. Safe for the intended single-editor CLI use; a concurrent editor
24
+ is the caller's responsibility. An optimistic-concurrency guard is tracked in
25
+ todo/procesio-surgical-optimistic-concurrency.md.
26
+ """
27
+ from __future__ import annotations
28
+
29
+ import argparse
30
+
31
+ from tools.procesio import formlint
32
+ from tools.procesio.actiondef import ActionDef
33
+ from tools.procesio.errors import NotPersisted, UsageError
34
+ from tools.procesio.handlers.common import add_force_arg, add_profile_arg, guard_unchanged
35
+
36
+ # Top-level DTO keys PUT /api/FormTemplate expects (PascalCase), mapped from the
37
+ # camelCase keys GET /api/FormTemplate/{id} returns. Kept explicit so an unexpected
38
+ # extra field on the GET is never echoed back into the PUT.
39
+ _PUT_KEYS = {
40
+ "Id": "id",
41
+ "Name": "name",
42
+ "IsPrivate": "isPrivate",
43
+ "Type": "type",
44
+ "Status": "status",
45
+ "State": "state",
46
+ "Assignees": "assignees",
47
+ "CustomUrl": "customUrl",
48
+ }
49
+
50
+
51
+ def build_put_body(form: dict, *, data: dict | None = None, name: str | None = None,
52
+ status: int | None = None, state: bool | None = None,
53
+ is_private: bool | None = None, assignees: list | None = None) -> dict:
54
+ """The single canonical GET-echo -> accepted-PUT-body transform for form surgery.
55
+
56
+ `PUT /api/FormTemplate` binds top-level keys by PascalCase (`Id`/`Name`/`Data`);
57
+ the camelCase GET echo (`id`/`name`/`data`) is rejected 403. Every surgical
58
+ save (set-code, set-element-event/config, form-update) routes through here so
59
+ no caller hand-rolls the camelCase PUT the server refuses.
60
+
61
+ `Data` round-trips verbatim from the echo unless `data` is given (the caller
62
+ already merged its change in). Top-level `name`/`status`/`state` are overridden
63
+ only when passed. `IsPrivate` is the reachability switch: `false` + `Status: 1` is what makes a
64
+ form answer to an anonymous visitor on its custom URL, and it is a PUBLISHING decision, so it is
65
+ never changed unless the caller asks. `CustomUrl` is ECHOED from the GET (the PUT ignores it either
66
+ way — a form's custom URL is a separate entity managed via /api/CustomUrl/*, so
67
+ echo and null are equivalent; verified live), and server metadata that isn't in
68
+ `_PUT_KEYS` is dropped.
69
+ """
70
+ for k in ("id", "name", "data"):
71
+ if not form.get(k):
72
+ raise UsageError(f"GET /api/FormTemplate echo is missing {k!r}; refusing to PUT")
73
+ dto = {k: form.get(src) for k, src in _PUT_KEYS.items()} # PascalCase echo incl. CustomUrl
74
+ dto["Data"] = form.get("data") or {} if data is None else data
75
+ if name is not None:
76
+ dto["Name"] = name
77
+ if status is not None:
78
+ dto["Status"] = status
79
+ if state is not None:
80
+ dto["State"] = bool(state)
81
+ if is_private is not None:
82
+ dto["IsPrivate"] = bool(is_private)
83
+ if assignees is not None: # re-derived task routing (dto.form.builder.reconcile_assignees)
84
+ dto["Assignees"] = assignees
85
+ return dto
86
+
87
+
88
+ def _code_key(client) -> str:
89
+ """The form-code-key for the environment this call runs against: one per
90
+ installation, never borrowed from another (form_code_keys)."""
91
+ from tools.procesio import form_code_keys
92
+ env = getattr(client, "env", None)
93
+ return form_code_keys.key_for(env.get("name") if isinstance(env, dict) else None)
94
+
95
+
96
+ def _fetch(client, form_id: str) -> dict:
97
+ body = client.get(f"/api/FormTemplate/{form_id}")
98
+ if isinstance(body, dict) and "result" in body and isinstance(body["result"], dict):
99
+ body = body["result"]
100
+ if not isinstance(body, dict) or "data" not in body:
101
+ raise UsageError(f"unexpected FormTemplate payload for {form_id!r}")
102
+ return body
103
+
104
+
105
+ def _decode(blob: str, key: str) -> dict:
106
+ """Decrypt a Data.code blob into {"CSS": str, "JAVASCRIPT": str}.
107
+
108
+ Two shapes both mean "no form-level code" and must not be treated as errors:
109
+ an empty/absent blob, and a blob that decrypts to explicit JSON nulls — the
110
+ latter is the designer's INITIAL state (the frontend seeds both slots to null),
111
+ so it is what every form that has never used "Switch to code" carries. Both are
112
+ normalized to empty strings here so callers can rely on getting strings.
113
+ """
114
+ if not blob:
115
+ return {"CSS": "", "JAVASCRIPT": ""}
116
+ from tools.procesio.dto.form import code_cipher
117
+ try:
118
+ raw = code_cipher.decrypt_code(blob, key)
119
+ except Exception as e: # noqa: BLE001 — wrong key and corrupt blob look alike
120
+ raise UsageError(
121
+ f"could not decrypt Data.code ({e}); the form-code-key stored for this "
122
+ f"environment does not match the blob this form was saved with (one key per "
123
+ f"installation: check it is THIS installation's)"
124
+ ) from e
125
+ return {"CSS": raw.get("CSS") or "", "JAVASCRIPT": raw.get("JAVASCRIPT") or ""}
126
+
127
+
128
+ def _read_text(inline, path, label: str):
129
+ if inline is not None and path:
130
+ raise UsageError(f"pass either --{label} or --{label}-file, not both")
131
+ if path:
132
+ with open(path, encoding="utf-8") as f:
133
+ return f.read()
134
+ return inline
135
+
136
+
137
+ # -- actions -----------------------------------------------------------------
138
+
139
+ def get_code(client, args) -> dict:
140
+ form = _fetch(client, args.id)
141
+ code = _decode(form["data"].get("code") or "", _code_key(client))
142
+ css, js = code.get("CSS", ""), code.get("JAVASCRIPT", "")
143
+ if args.css_out:
144
+ with open(args.css_out, "w", encoding="utf-8") as f:
145
+ f.write(css)
146
+ if args.js_out:
147
+ with open(args.js_out, "w", encoding="utf-8") as f:
148
+ f.write(js)
149
+ return {"id": args.id, "name": form.get("name"), "css": css, "javascript": js,
150
+ "css_bytes": len(css), "javascript_bytes": len(js)}
151
+
152
+
153
+ def set_code(client, args) -> dict:
154
+ css = _read_text(args.css, args.css_file, "css")
155
+ js = _read_text(args.javascript, args.js_file, "js")
156
+
157
+ if getattr(args, "clear", False):
158
+ # Recovery path. Every other route through this action DECRYPTS the existing blob first, so
159
+ # that omitting one side preserves it — which means a form saved under a different passphrase
160
+ # (a rotated key, another workspace, an import) becomes permanently uneditable: the decrypt
161
+ # fails before any write can happen. Clearing is the only repair that does not need the
162
+ # original key, so it deliberately never touches the cipher. The discarded blob is reported
163
+ # by LENGTH only; a value that cannot be decrypted must not be echoed either.
164
+ if css is not None or js is not None:
165
+ raise UsageError("--clear removes the form's code entirely; do not combine it with "
166
+ "--css/--css-file or --javascript/--js-file")
167
+ form = _fetch(client, args.id)
168
+ old = form["data"].get("code") or ""
169
+ result = {"id": args.id, "name": form.get("name"), "cleared": True,
170
+ "discarded_blob_bytes": len(old),
171
+ "elements": len(form["data"].get("elements") or [])}
172
+ if args.dry_run:
173
+ return {"dry_run": True, **result}
174
+ guard = guard_unchanged(lambda: _fetch(client, args.id), form, force=args.force)
175
+ data = dict(form["data"])
176
+ data["code"] = ""
177
+ client.put("/api/FormTemplate", build_put_body(form, data=data))
178
+ return {"updated": True, "concurrency": guard, **result}
179
+
180
+ if css is None and js is None:
181
+ raise UsageError("nothing to set: pass --css/--css-file and/or --javascript/--js-file, "
182
+ "or --clear to remove the form's code entirely")
183
+
184
+ key = _code_key(client)
185
+ form = _fetch(client, args.id)
186
+ previous = _decode(form["data"].get("code") or "", key)
187
+ # Omitting one side PRESERVES it — restyling should never silently drop the JS.
188
+ css = previous["CSS"] if css is None else css
189
+ js = previous["JAVASCRIPT"] if js is None else js
190
+
191
+ from tools.procesio.dto.form import code_cipher
192
+ blob = code_cipher.encrypt_code(js, css, key) if (css or js) else ""
193
+
194
+ result = {
195
+ "id": args.id, "name": form.get("name"),
196
+ "css_bytes": len(css), "javascript_bytes": len(js),
197
+ "previous": {"css": previous["CSS"], "javascript": previous["JAVASCRIPT"]},
198
+ "elements": len(form["data"].get("elements") or []),
199
+ }
200
+ warnings = formlint.lint_form_code_scope(css, js)
201
+ if warnings:
202
+ result["warnings"] = warnings
203
+ if args.dry_run:
204
+ return {"dry_run": True, **result}
205
+
206
+ guard = guard_unchanged(lambda: _fetch(client, args.id), form, force=args.force)
207
+ data = dict(form["data"])
208
+ data["code"] = blob
209
+ client.put("/api/FormTemplate", build_put_body(form, data=data))
210
+ verified = _verify_persisted(client, args.id, key, css, js, previous)
211
+ return {"updated": True, "verified": verified, "concurrency": guard, **result}
212
+
213
+
214
+ # Seen live (2026-10-18, Internal-PROD): POST /api/FormTemplate, PUT /api/FormTemplate and
215
+ # .../duplicate all answered 2xx while dropping Data entirely: a new form or a duplicate came back
216
+ # with data: null, and an update moved updatedOn but left every Data field (code, browserTitle)
217
+ # as it was. A 2xx alone therefore proves nothing about a form write; read it back.
218
+ def _verify_persisted(client, form_id: str, key: str, css: str, js: str, previous: dict):
219
+ """Read the form back and compare. True = stored as sent; None = the read-back was not a
220
+ form payload (cannot tell); raises NotPersisted when the server kept something else."""
221
+ try:
222
+ after = _fetch(client, form_id)
223
+ except UsageError:
224
+ return None
225
+ got = _decode(after["data"].get("code") or "", key)
226
+ if got["CSS"] == css and got["JAVASCRIPT"] == js:
227
+ return True
228
+ kept_previous = got["CSS"] == previous["CSS"] and got["JAVASCRIPT"] == previous["JAVASCRIPT"]
229
+ raise NotPersisted(
230
+ "the PUT was accepted but the form still holds "
231
+ + ("its PREVIOUS code. " if kept_previous else "different code. ")
232
+ + ("PROCESIO has been seen accepting form writes while dropping Data altogether: create a tiny "
233
+ "test form and read it back - data: null there means the platform is not storing form "
234
+ "content, and no retry will help. Otherwise another editor saved the form at the same time."),
235
+ {"sent_bytes": len(css.encode("utf-8")) + len(js.encode("utf-8")),
236
+ "stored_bytes": len(got["CSS"].encode("utf-8")) + len(got["JAVASCRIPT"].encode("utf-8")),
237
+ "kept_previous": kept_previous})
238
+
239
+
240
+ def _get_args(p: argparse.ArgumentParser) -> None:
241
+ add_profile_arg(p)
242
+ p.add_argument("--id", required=True, help="form template id")
243
+ p.add_argument("--css-out", dest="css_out", help="also write the CSS to this file")
244
+ p.add_argument("--js-out", dest="js_out", help="also write the JavaScript to this file")
245
+
246
+
247
+ def _set_args(p: argparse.ArgumentParser) -> None:
248
+ add_profile_arg(p)
249
+ p.add_argument("--id", required=True, help="form template id")
250
+ p.add_argument("--css", help="CSS source as an inline string")
251
+ p.add_argument("--css-file", dest="css_file", help="path to a .css file")
252
+ p.add_argument("--javascript", help="JavaScript source as an inline string")
253
+ p.add_argument("--js-file", dest="js_file", help="path to a .js file")
254
+ p.add_argument("--clear", action="store_true",
255
+ help="remove the form's code entirely without decrypting it - the only repair "
256
+ "for a blob the stored form-code-key cannot open")
257
+ p.add_argument("--dry-run", dest="dry_run", action="store_true",
258
+ help="report the change (and the previous code) without writing")
259
+ add_force_arg(p)
260
+
261
+
262
+ ACTIONS = {
263
+ "form-get-code": ActionDef(
264
+ func=get_code, add_args=_get_args, needs_client=True,
265
+ description="Read a form's global CSS + JavaScript (decrypts Data.code).",
266
+ ),
267
+ "form-set-code": ActionDef(
268
+ func=set_code, add_args=_set_args, needs_client=True,
269
+ description="Set a form's global CSS + JavaScript in place (surgical: only Data.code changes; "
270
+ "omitted side is preserved; returns the previous code). Reads the form back after the "
271
+ "write and fails with not_persisted if the server kept other code (PROCESIO has been seen "
272
+ "answering 2xx while dropping the form's Data). --clear removes the code "
273
+ "entirely WITHOUT decrypting it, which is the only repair for a blob the stored "
274
+ "form-code-key cannot open. Returns `warnings` when the code mounts UI on "
275
+ "document.body or styles :root/html/body without propagating the form's CSS "
276
+ "scope attribute (those styles do not apply)."),
277
+ }