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,330 @@
1
+ """The public Python API other tools import: open_session, run_steps, get_text,
2
+ screenshot, save_session - all with an injected FakeDriver (no real browser)."""
3
+ from __future__ import annotations
4
+
5
+ import pytest
6
+
7
+ from tools.web import api, sessions
8
+ from tools.web.errors import SessionError, UsageError
9
+
10
+
11
+ def _seed(name="linkedin"):
12
+ sessions.write_state(name, {"cookies": [{"name": "sid", "value": "v"}], "origins": []})
13
+
14
+
15
+ def test_render_pdf_sessionless_writes_pdf(tmp_path, driver_factory):
16
+ out = tmp_path / "invoice.pdf"
17
+ res = api.render_pdf("<h1>hi</h1>", str(out), fmt="Letter",
18
+ driver_factory=driver_factory)
19
+ d = driver_factory.built[0]
20
+ # session-less: no storageState, no user_data_dir, headless
21
+ assert d.init["storage_state"] is None and d.init["user_data_dir"] is None
22
+ assert d.init["headless"] is True
23
+ call = [kw for m, kw in d.calls if m == "render_pdf"][0]
24
+ assert call["html"] == "<h1>hi</h1>" and call["fmt"] == "Letter"
25
+ assert d.closed is True # browser always torn down
26
+ assert res["out"] == str(out) and res["bytes"] > 0
27
+ assert out.read_bytes().startswith(b"%PDF")
28
+
29
+
30
+ def test_render_pdf_custom_sheet_passes_size_and_margin(tmp_path, driver_factory):
31
+ # A roll-up / poster needs an exact sheet, not a paper name.
32
+ out = tmp_path / "rollup.pdf"
33
+ api.render_pdf("<div>x</div>", str(out), width="1000mm", height="2000mm", margin="0",
34
+ driver_factory=driver_factory)
35
+ call = [kw for m, kw in driver_factory.built[0].calls if m == "render_pdf"][0]
36
+ assert (call["width"], call["height"], call["margin"]) == ("1000mm", "2000mm", "0")
37
+
38
+
39
+ def test_render_pdf_defaults_keep_paper_format(tmp_path, driver_factory):
40
+ out = tmp_path / "doc.pdf"
41
+ api.render_pdf("<p>x</p>", str(out), driver_factory=driver_factory)
42
+ call = [kw for m, kw in driver_factory.built[0].calls if m == "render_pdf"][0]
43
+ assert call["fmt"] == "A4" and call["width"] is None and call["margin"] is None
44
+
45
+
46
+ def test_open_session_loads_state_and_starts(isolated_sessions, driver_factory):
47
+ _seed()
48
+ d = api.open_session("linkedin", url="https://x.test", driver_factory=driver_factory)
49
+ assert d.started is True
50
+ # storageState from the saved file was handed to the factory
51
+ assert d.init["storage_state"]["cookies"][0]["value"] == "v"
52
+ # url -> a goto happened
53
+ assert ("goto", {"url": "https://x.test", "timeout": None}) in d.calls
54
+
55
+
56
+ def test_open_session_missing_raises(isolated_sessions, driver_factory):
57
+ with pytest.raises(SessionError):
58
+ api.open_session("nope", driver_factory=driver_factory)
59
+
60
+
61
+ def test_open_session_auto_detects_persistent_profile(isolated_sessions, driver_factory):
62
+ # A `<name>.profile` dir (saved via --persistent) is used WITHOUT any
63
+ # storageState — and without the caller passing user_data_dir.
64
+ prof = sessions.profile_dir("gprof")
65
+ prof.mkdir()
66
+ (prof / "Default").write_text("x", encoding="utf-8") # non-empty
67
+ d = api.open_session("gprof", driver_factory=driver_factory)
68
+ assert d.started is True
69
+ assert d.init["user_data_dir"] == str(prof)
70
+ assert d.init["storage_state"] is None
71
+
72
+
73
+ def test_run_steps_end_to_end_and_closes(isolated_sessions, driver_factory):
74
+ _seed()
75
+ out = api.run_steps(
76
+ "linkedin",
77
+ [{"do": "extract_text", "selector": "h1", "name": "title"}],
78
+ url="https://x.test",
79
+ driver_factory=driver_factory,
80
+ )
81
+ assert out["session"] == "linkedin"
82
+ assert "title" in out["results"]
83
+ d = driver_factory.built[0]
84
+ assert d.closed is True # always torn down
85
+
86
+
87
+ def test_run_steps_headed_flag_threads_through(isolated_sessions, driver_factory):
88
+ _seed()
89
+ api.run_steps("linkedin", [], headless=False, driver_factory=driver_factory)
90
+ assert driver_factory.built[0].init["headless"] is False
91
+
92
+
93
+ def test_get_text_with_wait_and_selector(isolated_sessions, driver_factory):
94
+ _seed()
95
+ out = api.get_text("linkedin", "https://x.test", selector="main",
96
+ wait="#ready", driver_factory=driver_factory)
97
+ assert out["session"] == "linkedin"
98
+ assert out["selector"] == "main"
99
+ d = driver_factory.built[0]
100
+ methods = d.methods()
101
+ assert "wait_for" in methods and "extract_text" in methods
102
+ assert d.closed is True
103
+
104
+
105
+ def test_screenshot_full_page_default(isolated_sessions, driver_factory):
106
+ _seed()
107
+ out = api.screenshot("linkedin", "https://x.test", "shot.png",
108
+ driver_factory=driver_factory)
109
+ assert out["path"] == "shot.png"
110
+ shot = [kw for m, kw in driver_factory.built[0].calls if m == "screenshot"][0]
111
+ assert shot["full_page"] is True
112
+
113
+
114
+ def test_save_session_writes_state_after_signal(isolated_sessions, driver_factory):
115
+ signalled = {"v": False}
116
+
117
+ def wait_for_signal():
118
+ signalled["v"] = True
119
+
120
+ out = api.save_session("newsite", "https://login.test",
121
+ wait_for_signal=wait_for_signal,
122
+ driver_factory=driver_factory)
123
+ assert signalled["v"] is True # human signal was awaited
124
+ assert out["session"] == "newsite"
125
+ # storageState captured from the (headed) driver and persisted
126
+ assert sessions.exists("newsite")
127
+ saved = sessions.load_state("newsite")
128
+ assert saved["cookies"][0]["name"] == "sid"
129
+ # headed browser was requested
130
+ assert driver_factory.built[0].init["headless"] is False
131
+ assert driver_factory.built[0].closed is True
132
+
133
+
134
+ def test_save_session_persistent_captures_cookie_sidecar(isolated_sessions, driver_factory):
135
+ """A persistent save snapshots live cookies (incl. session-scoped) to a
136
+ sidecar, because the on-disk profile won't persist them itself."""
137
+ out = api.save_session("ryv", "https://example.ryver.com",
138
+ wait_for_signal=lambda: None, persistent=True,
139
+ driver_factory=driver_factory)
140
+ assert out["persistent"] is True
141
+ assert out["cookies_saved"] == 1 # FakeDriver returns one cookie
142
+ assert sessions.cookies_exist("ryv")
143
+ saved = sessions.load_cookies("ryv")
144
+ assert saved[0]["name"] == "sid" and saved[0]["expires"] == -1
145
+ # cookies captured AFTER the human signal and BEFORE close
146
+ methods = driver_factory.built[0].methods()
147
+ assert methods.index("get_cookies") < methods.index("close")
148
+
149
+
150
+ def test_open_session_persistent_reinjects_cookies_before_navigation(isolated_sessions, driver_factory):
151
+ """Opening a persistent profile that has a cookie sidecar must re-inject the
152
+ cookies into the fresh context BEFORE navigating, so the first request is
153
+ authenticated."""
154
+ prof = sessions.profile_dir("ryv")
155
+ prof.mkdir()
156
+ (prof / "Default").write_text("x", encoding="utf-8")
157
+ sessions.write_cookies("ryv", [{"name": "sid", "value": "z",
158
+ "domain": ".ringhel.ryver.com", "path": "/",
159
+ "expires": -1}])
160
+ d = api.open_session("ryv", url="https://example.ryver.com",
161
+ driver_factory=driver_factory)
162
+ assert d.injected_cookies and d.injected_cookies[0]["value"] == "z"
163
+ methods = d.methods()
164
+ assert methods.index("add_cookies") < methods.index("goto") # inject, THEN navigate
165
+
166
+
167
+ def test_open_session_persistent_without_sidecar_skips_injection(isolated_sessions, driver_factory):
168
+ """No sidecar -> no add_cookies call (back-compat for IndexedDB-auth
169
+ profiles like WhatsApp that never had one)."""
170
+ prof = sessions.profile_dir("wa")
171
+ prof.mkdir()
172
+ (prof / "Default").write_text("x", encoding="utf-8")
173
+ d = api.open_session("wa", url="https://web.whatsapp.com",
174
+ driver_factory=driver_factory)
175
+ assert "add_cookies" not in d.methods()
176
+ assert d.injected_cookies == []
177
+
178
+
179
+ def test_save_session_signal_order(isolated_sessions, driver_factory):
180
+ """storage_state must be captured AFTER the human signal, not before."""
181
+ order = []
182
+
183
+ def wait_for_signal():
184
+ order.append("signal")
185
+
186
+ # wrap the factory to record when storage_state is read
187
+ base = driver_factory
188
+
189
+ def factory(**kw):
190
+ d = base(**kw)
191
+ orig = d.storage_state
192
+
193
+ def traced():
194
+ order.append("capture")
195
+ return orig()
196
+ d.storage_state = traced
197
+ return d
198
+
199
+ api.save_session("ordered", "https://login.test",
200
+ wait_for_signal=wait_for_signal, driver_factory=factory)
201
+ assert order == ["signal", "capture"]
202
+
203
+
204
+ # --- non-stdin login wait (agent-driven save-session) -----------------------
205
+
206
+ def test_save_session_wait_seconds_detects_login(isolated_sessions, driver_factory,
207
+ monkeypatch):
208
+ """With --wait-seconds the browser is held open WITHOUT touching stdin, and
209
+ the wait ends as soon as the address bar leaves the login host."""
210
+ monkeypatch.setattr(api, "_POLL_SECONDS", 0)
211
+ monkeypatch.setattr(api, "_SETTLE_SECONDS", 0)
212
+
213
+ def boom(): # stdin must never be consulted
214
+ raise AssertionError("save_session must not block on stdin")
215
+ monkeypatch.setattr(api, "_block_on_enter", boom)
216
+
217
+ out = api.save_session("goog", "https://drive.google.com/drive/my-drive",
218
+ persistent=True, wait_seconds=30,
219
+ wait_until_url_excludes="accounts.google.com",
220
+ driver_factory=driver_factory)
221
+ assert out["waited_for"] == "url"
222
+ assert out["login_detected"] is True # FakeDriver url is off the login host
223
+ assert out["final_url"] == "https://example.com/after" # FakeDriver post-nav url
224
+
225
+
226
+ def test_save_session_wait_seconds_reports_timeout(isolated_sessions, monkeypatch):
227
+ """Still on the login host when time runs out -> login_detected False, so a
228
+ half-authenticated save is never mistaken for success. This is the exact
229
+ case that silently produced a broken `google` session (see
230
+ WEB-AUTOMATION-NOTES.md)."""
231
+ from tools.web.tests.conftest import FakeDriver
232
+
233
+ monkeypatch.setattr(api, "_POLL_SECONDS", 0)
234
+ monkeypatch.setattr(api, "_SETTLE_SECONDS", 0)
235
+
236
+ def stuck_factory(**kwargs):
237
+ # never leaves the login host, however long we wait
238
+ return FakeDriver(url="https://accounts.google.com/signin", **kwargs)
239
+
240
+ out = api.save_session("goog2", "https://accounts.google.com/signin",
241
+ persistent=True, wait_seconds=1,
242
+ wait_until_url_excludes="accounts.google.com",
243
+ driver_factory=stuck_factory)
244
+ assert out["login_detected"] is False
245
+ assert "final_url" not in out
246
+
247
+
248
+ def test_save_session_rejects_nonpositive_wait(isolated_sessions, driver_factory):
249
+ with pytest.raises(UsageError):
250
+ api.save_session("goog3", "https://example.test", wait_seconds=0,
251
+ driver_factory=driver_factory)
252
+
253
+
254
+ # --- human-handoff hold (agent stages, human commits) ----------------------
255
+
256
+ def _steps():
257
+ return [{"do": "fill", "selector": "#name", "text": "x"}]
258
+
259
+
260
+ def test_run_hold_ends_early_when_selector_appears(isolated_sessions, driver_factory,
261
+ monkeypatch):
262
+ """The hold exists so a human can click Submit. FakeDriver.wait_for always
263
+ resolves, i.e. the confirmation element is already there -> reason
264
+ 'selector', completed True."""
265
+ monkeypatch.setattr(api, "_POLL_SECONDS", 0)
266
+
267
+ _seed()
268
+ out = api.run_steps("linkedin", _steps(), headless=False, hold_seconds=30,
269
+ hold_until_selector="text=Thank",
270
+ driver_factory=driver_factory)
271
+ assert out["hold"]["completed"] is True
272
+ assert out["hold"]["reason"] == "selector"
273
+
274
+
275
+ def test_run_hold_ends_early_when_url_leaves_host(isolated_sessions, driver_factory,
276
+ monkeypatch):
277
+ monkeypatch.setattr(api, "_POLL_SECONDS", 0)
278
+
279
+ _seed()
280
+ out = api.run_steps("linkedin", _steps(), headless=False, hold_seconds=30,
281
+ hold_until_url_excludes="form.example.test",
282
+ driver_factory=driver_factory)
283
+ assert out["hold"]["completed"] is True
284
+ assert out["hold"]["reason"] == "url"
285
+
286
+
287
+ def test_run_hold_timeout_is_success_not_failure(isolated_sessions, monkeypatch):
288
+ """The regression this feature exists for: an idle human must NOT turn a
289
+ successful fill into a failed run. No raise, steps' results intact."""
290
+ from tools.web.tests.conftest import FakeDriver
291
+
292
+ monkeypatch.setattr(api, "_POLL_SECONDS", 0)
293
+
294
+ class NeverDriver(FakeDriver):
295
+ def wait_for(self, selector, *, timeout=None):
296
+ raise RuntimeError("selector never appears")
297
+
298
+ _seed()
299
+ out = api.run_steps("linkedin", _steps(), headless=False, hold_seconds=1,
300
+ hold_until_selector="text=Thank",
301
+ driver_factory=lambda **kw: NeverDriver(**kw))
302
+ assert out["hold"]["completed"] is False
303
+ assert out["hold"]["reason"] == "timeout"
304
+ assert out["hold"]["held_seconds"] >= 0
305
+ assert "results" in out # the steps still ran
306
+
307
+
308
+ def test_run_hold_requires_headed(isolated_sessions, driver_factory):
309
+ with pytest.raises(UsageError):
310
+ api.run_steps("linkedin", _steps(), headless=True, hold_seconds=30,
311
+ driver_factory=driver_factory)
312
+
313
+
314
+ def test_run_hold_rejects_nonpositive(isolated_sessions, driver_factory):
315
+ with pytest.raises(UsageError):
316
+ api.run_steps("linkedin", _steps(), headless=False, hold_seconds=0,
317
+ driver_factory=driver_factory)
318
+
319
+
320
+ def test_run_hold_conditions_require_hold_seconds(isolated_sessions, driver_factory):
321
+ with pytest.raises(UsageError):
322
+ api.run_steps("linkedin", _steps(), headless=False,
323
+ hold_until_selector="text=Thank",
324
+ driver_factory=driver_factory)
325
+
326
+
327
+ def test_run_without_hold_has_no_hold_block(isolated_sessions, driver_factory):
328
+ _seed()
329
+ out = api.run_steps("linkedin", _steps(), driver_factory=driver_factory)
330
+ assert "hold" not in out
@@ -0,0 +1,190 @@
1
+ """Tests for `web archive-document`.
2
+
3
+ The capture is evidence, so the properties that matter are not "did it write a
4
+ file" but: the original is byte-identical to what the publisher served, the hash
5
+ in the header is the hash of THAT file, the extraction never silently loses the
6
+ document's text, and a date the document states about itself is reported rather
7
+ than reconciled. Each test below pins one of those.
8
+
9
+ No network: the fetch path is exercised through --file, and the stylesheet
10
+ inliner is driven with a stubbed requests module.
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import hashlib
15
+ import json
16
+ import subprocess
17
+ import sys
18
+ from pathlib import Path
19
+
20
+ import pytest
21
+
22
+ FRAMEWORK_ROOT = Path(__file__).resolve().parents[3]
23
+ if str(FRAMEWORK_ROOT) not in sys.path:
24
+ sys.path.insert(0, str(FRAMEWORK_ROOT))
25
+
26
+ from tools.web.handlers import archive # noqa: E402
27
+ from tools.web.errors import UsageError # noqa: E402
28
+
29
+
30
+ class _Args:
31
+ """Minimal stand-in for the parsed argparse namespace."""
32
+
33
+ def __init__(self, **kw):
34
+ defaults = dict(url=None, file=None, source_url=None, out_dir=None,
35
+ name=None, title=None, timeout=5, no_self_contained=True)
36
+ defaults.update(kw)
37
+ for k, v in defaults.items():
38
+ setattr(self, k, v)
39
+
40
+
41
+ HTML = b"""<html><head><title>Terms & Conditions | ACME</title>
42
+ <link rel="stylesheet" href="/s.css"></head>
43
+ <body><h1>Terms</h1><p>Last updated: 10 August 2021</p>
44
+ <p>Client must not resell the Technology.</p>
45
+ <script>var x=1;</script></body></html>"""
46
+
47
+
48
+ def _run(tmp_path, **kw):
49
+ src = tmp_path / "in.html"
50
+ src.write_bytes(kw.pop("body", HTML))
51
+ return archive.archive_document(
52
+ _Args(file=str(src), out_dir=str(tmp_path / "out"), name="terms", **kw))
53
+
54
+
55
+ def test_original_is_byte_identical_and_hash_matches_it(tmp_path):
56
+ """The stored original must equal the input byte for byte, and the reported
57
+ sha256 must be the hash of that file - not of the extraction, and not of a
58
+ re-serialised parse tree. This is the whole basis for comparing a later
59
+ fetch against this one."""
60
+ res = _run(tmp_path)
61
+ original = Path(res["files"]["original"])
62
+ assert original.read_bytes() == HTML
63
+ assert res["sha256"]["original"] == hashlib.sha256(HTML).hexdigest()
64
+
65
+
66
+ def test_extraction_keeps_document_text_and_drops_only_script(tmp_path):
67
+ """Dropping a region to tidy the extraction risks dropping a clause that
68
+ happens to sit in it, so only script/style are removed."""
69
+ res = _run(tmp_path)
70
+ text = Path(res["files"]["extraction"]).read_text(encoding="utf-8")
71
+ assert "Client must not resell the Technology." in text
72
+ assert "var x=1" not in text
73
+
74
+
75
+ def test_provenance_header_carries_source_and_hash(tmp_path):
76
+ """An extraction that travels without its source and fetch date becomes an
77
+ unattributable quote the first time someone pastes it into a brief."""
78
+ res = _run(tmp_path, source_url="https://example.com/terms")
79
+ header = Path(res["files"]["extraction"]).read_text(encoding="utf-8")[:1200]
80
+ assert "https://example.com/terms" in header
81
+ assert res["sha256"]["original"] in header
82
+ assert "Fetched at (UTC)" in header
83
+
84
+
85
+ def test_title_read_from_the_document_unless_overridden(tmp_path):
86
+ assert _run(tmp_path)["title"] == "Terms & Conditions | ACME"
87
+ assert _run(tmp_path, title="Pinned")["title"] == "Pinned"
88
+
89
+
90
+ def test_self_contained_copy_is_written_only_when_asked(tmp_path):
91
+ assert "self_contained" not in _run(tmp_path)["files"]
92
+
93
+
94
+ def test_date_candidates_are_reported_not_reconciled(tmp_path):
95
+ """Two different dates on one document is a finding about the document. The
96
+ action must surface both rather than pick one."""
97
+ body = (b"<html><body><p>Last updated: 10 August 2021</p>"
98
+ b"<p>Effective 19/12/2023</p></body></html>")
99
+ res = _run(tmp_path, body=body)
100
+ dates = [d["date"] for d in res["document_date_candidates"]]
101
+ assert "10 August 2021" in dates
102
+ assert "19/12/2023" in dates
103
+
104
+
105
+ def test_a_bare_date_with_no_version_context_is_not_claimed_as_the_date(tmp_path):
106
+ """A date mentioned in passing is not the document's own date. Only dates
107
+ near version wording are reported, so the caller is not handed a false
108
+ 'this document is dated X'."""
109
+ body = b"<html><body><p>The contract began on 01/01/2020 in Bucharest.</p></body></html>"
110
+ assert _run(tmp_path, body=body)["document_date_candidates"] == []
111
+
112
+
113
+ def test_pdf_is_detected_by_magic_bytes_not_extension(tmp_path):
114
+ """A PDF served without a .pdf path or content-type must still be stored as
115
+ a .pdf and text-extracted as one."""
116
+ src = tmp_path / "doc.bin"
117
+ src.write_bytes(b"%PDF-1.4\n% not a real pdf")
118
+ res = archive.archive_document(
119
+ _Args(file=str(src), out_dir=str(tmp_path / "out"), name="agreement"))
120
+ assert res["kind"] == "pdf"
121
+ assert Path(res["files"]["original"]).suffix == ".pdf"
122
+
123
+
124
+ @pytest.mark.parametrize("kw", [
125
+ dict(), # neither url nor file
126
+ dict(url="https://x/y", file="z.html"), # both
127
+ ])
128
+ def test_exactly_one_source_is_required(tmp_path, kw):
129
+ with pytest.raises(UsageError):
130
+ archive.archive_document(
131
+ _Args(out_dir=str(tmp_path), name="n", **kw))
132
+
133
+
134
+ def test_name_must_not_escape_the_out_dir(tmp_path):
135
+ """--name becomes a folder; a path separator in it would write outside the
136
+ collection."""
137
+ for bad in ("../evil", "a/b", "a\\b", " "):
138
+ with pytest.raises(UsageError):
139
+ archive.archive_document(
140
+ _Args(file=str(tmp_path), out_dir=str(tmp_path), name=bad))
141
+
142
+
143
+ def test_stylesheets_are_inlined_with_urls_made_absolute(tmp_path, monkeypatch):
144
+ """The inlined copy has to render offline, and url() inside a stylesheet is
145
+ relative to the STYLESHEET, not the page - left alone it loses its fonts."""
146
+ class _Resp:
147
+ status_code = 200
148
+ text = "body{background:url('img/bg.png')}"
149
+
150
+ monkeypatch.setattr("requests.get", lambda *a, **k: _Resp())
151
+ soup = archive._soup(HTML)
152
+ assert archive._inline_stylesheets(soup, "https://example.com/terms", 5) == 1
153
+ out = str(soup)
154
+ assert "inlined from https://example.com/s.css" in out
155
+ assert "url('https://example.com/img/bg.png')" in out
156
+ assert "<link" not in out
157
+
158
+
159
+ def test_a_failing_stylesheet_degrades_but_never_aborts_the_capture(tmp_path, monkeypatch):
160
+ """Losing a stylesheet must not cost us the document."""
161
+ def _boom(*a, **k):
162
+ raise RuntimeError("network down")
163
+
164
+ monkeypatch.setattr("requests.get", _boom)
165
+ soup = archive._soup(HTML)
166
+ assert archive._inline_stylesheets(soup, "https://example.com/t", 5) == 0
167
+
168
+
169
+ def test_manifest_declares_every_runtime_action(tmp_path):
170
+ """Manifest is the source of truth (Hard rule 3): an action reachable at
171
+ runtime but absent from tool.yaml is a contract that drifted."""
172
+ import yaml
173
+ from tools.web import main as web_main
174
+ manifest = yaml.safe_load((FRAMEWORK_ROOT / "tools/web/tool.yaml").read_text(encoding="utf-8"))
175
+ declared = {a["name"] for a in manifest["actions"]}
176
+ assert "archive-document" in declared
177
+ assert set(web_main.ACTIONS) == declared
178
+
179
+
180
+ def test_cli_emits_one_json_object_on_stdout(tmp_path):
181
+ """JSON in, JSON out (Hard rule 2)."""
182
+ src = tmp_path / "in.html"
183
+ src.write_bytes(HTML)
184
+ proc = subprocess.run(
185
+ [sys.executable, str(FRAMEWORK_ROOT / "scripts/run-tool.py"), "web",
186
+ "archive-document", "--file", str(src), "--out-dir",
187
+ str(tmp_path / "out"), "--name", "terms"],
188
+ capture_output=True, text=True, cwd=str(FRAMEWORK_ROOT))
189
+ assert proc.returncode == 0, proc.stderr
190
+ assert json.loads(proc.stdout)["name"] == "terms"
@@ -0,0 +1,138 @@
1
+ """web-tool broker routing tests: generic run/get-text/screenshot against a
2
+ broker-OWNED session are translated to a web-steps op on the owning broker;
3
+ unowned sessions, --direct, --channel and injected factories stay in-process.
4
+ save-session/delete-session stop the owning broker first. No real broker is
5
+ ever spawned (conftest autouse sets all *_DIRECT; tests stub the lib client)."""
6
+ from __future__ import annotations
7
+
8
+ import pytest
9
+
10
+ from tools._lib.webserialize import client as ws_client
11
+ from tools.web import brokered
12
+ from tools.web.main import dispatch
13
+
14
+
15
+ def _unroute(monkeypatch):
16
+ for env in ("WHATSAPP_DIRECT", "RYVER_WEB_DIRECT",
17
+ "FGO_WEB_DIRECT", "MIRRO_DIRECT"):
18
+ monkeypatch.delenv(env, raising=False)
19
+
20
+
21
+ @pytest.fixture
22
+ def captured_web_steps(monkeypatch):
23
+ """Stub the lib's web_steps; records the submission and returns a canned
24
+ run_steps-shaped result tagged as served by the broker."""
25
+ seen = {}
26
+
27
+ def fake(cfg, session, steps, *, url=None, headless=True,
28
+ read_timeout=None, dispatch_direct=None):
29
+ seen.update(tool=cfg.tool, session=session, steps=steps,
30
+ url=url, headless=headless)
31
+ return {"session": session,
32
+ "results": {"text": "PAGE TEXT"}, "screenshots": ["x.png"],
33
+ "final_url": "https://final/", "diagnostics": {},
34
+ "via": "service", "service_queue_wait_ms": 3}
35
+
36
+ monkeypatch.setattr(ws_client, "web_steps", fake)
37
+ return seen
38
+
39
+
40
+ def test_run_routes_to_owning_broker(monkeypatch, captured_web_steps):
41
+ _unroute(monkeypatch)
42
+ out = dispatch("run", ["--session", "ryver", "--url", "https://r/",
43
+ "--actions", '[{"do": "extract_text", "name": "t"}]'])
44
+ assert captured_web_steps["tool"] == "ryver-web"
45
+ assert captured_web_steps["session"] == "ryver"
46
+ assert captured_web_steps["steps"] == [{"do": "extract_text", "name": "t"}]
47
+ assert out["via"] == "service"
48
+
49
+
50
+ def test_get_text_translation_and_reshape(monkeypatch, captured_web_steps):
51
+ _unroute(monkeypatch)
52
+ out = dispatch("get-text", ["--session", "whatsapp", "--url", "https://w/",
53
+ "--selector", "#main", "--wait", "#pane-side"])
54
+ assert captured_web_steps["steps"] == [
55
+ {"do": "wait_for", "selector": "#pane-side"},
56
+ {"do": "extract_text", "name": "text", "selector": "#main"},
57
+ ]
58
+ assert out["text"] == "PAGE TEXT" and out["session"] == "whatsapp"
59
+ assert out["final_url"] == "https://final/" and out["via"] == "service"
60
+
61
+
62
+ def test_screenshot_translation(monkeypatch, captured_web_steps, tmp_path):
63
+ _unroute(monkeypatch)
64
+ target = str(tmp_path / "shot.png")
65
+ out = dispatch("screenshot", ["--session", "fgo", "--url", "https://f/",
66
+ "--out", target, "--viewport-only"])
67
+ assert captured_web_steps["steps"] == [
68
+ {"do": "screenshot", "path": target, "full_page": False}]
69
+ assert out["path"] == target and out["via"] == "service"
70
+
71
+
72
+ def test_unowned_session_stays_direct(monkeypatch, driver_factory, isolated_sessions):
73
+ _unroute(monkeypatch)
74
+ monkeypatch.setattr(ws_client, "web_steps",
75
+ lambda *a, **k: pytest.fail("unowned must not route"))
76
+ (isolated_sessions / "google.json").write_text('{"cookies": [], "origins": []}',
77
+ encoding="utf-8")
78
+ out = dispatch("get-text", ["--session", "google", "--url", "https://g/"],
79
+ driver_factory=driver_factory)
80
+ assert "text" in out
81
+
82
+
83
+ def test_direct_and_channel_and_env_stay_local(monkeypatch):
84
+ _unroute(monkeypatch)
85
+ from types import SimpleNamespace as NS
86
+ base = dict(direct=False, channel=None, session="whatsapp")
87
+ assert brokered.eligible(NS(**base), driver_factory=None,
88
+ allow_service=True) is not None
89
+ assert brokered.eligible(NS(**{**base, "direct": True}),
90
+ driver_factory=None, allow_service=True) is None
91
+ assert brokered.eligible(NS(**{**base, "channel": "chrome"}),
92
+ driver_factory=None, allow_service=True) is None
93
+ assert brokered.eligible(NS(**base), driver_factory=object(),
94
+ allow_service=True) is None
95
+ assert brokered.eligible(NS(**{**base, "session": "google"}),
96
+ driver_factory=None, allow_service=True) is None
97
+ monkeypatch.setenv("WHATSAPP_DIRECT", "1") # owning tool's kill switch
98
+ assert brokered.eligible(NS(**base), driver_factory=None,
99
+ allow_service=True) is None
100
+ monkeypatch.delenv("WHATSAPP_DIRECT")
101
+ monkeypatch.setenv("WHATSAPP_SERVICE_WORKER", "1") # inside the worker
102
+ assert brokered.eligible(NS(**base), driver_factory=None,
103
+ allow_service=True) is None
104
+
105
+
106
+ def test_fallback_result_is_not_reshaped(monkeypatch):
107
+ """When the broker can't start, web_steps falls back to the DIRECT handler
108
+ whose result is already final — route() must return it untouched."""
109
+ _unroute(monkeypatch)
110
+ monkeypatch.setattr(ws_client, "ensure_running", lambda cfg, **k: None)
111
+ from types import SimpleNamespace as NS
112
+ parsed = NS(session="ryver", url="https://r/", selector=None, wait=None,
113
+ headed=False, direct=False, channel=None)
114
+ cfg = brokered.eligible(parsed, driver_factory=None, allow_service=True)
115
+ result = brokered.route(cfg, "get-text", parsed,
116
+ dispatch_direct=lambda: {"text": "DIRECT",
117
+ "session": "ryver"})
118
+ assert result["text"] == "DIRECT" and result["via"] == "direct-fallback"
119
+
120
+
121
+ def test_save_session_stops_owning_broker(monkeypatch, isolated_sessions):
122
+ from tools.web.handlers import sessmgmt
123
+ stopped = {}
124
+ monkeypatch.setattr(ws_client, "ping", lambda cfg, **k: {"pong": True})
125
+ monkeypatch.setattr(ws_client, "stop",
126
+ lambda cfg, **k: stopped.setdefault("tool", cfg.tool) or True)
127
+ monkeypatch.setattr(sessmgmt.api, "save_session",
128
+ lambda name, url, channel=None, persistent=False, **kw:
129
+ {"session": name, "url": url, "persistent": persistent})
130
+ from types import SimpleNamespace as NS
131
+ out = sessmgmt.save_session(NS(name="whatsapp", url="https://w/",
132
+ channel=None, persistent=True))
133
+ assert stopped["tool"] == "whatsapp-personal"
134
+ assert out["broker_stopped"] == "whatsapp-personal"
135
+
136
+ out = sessmgmt.save_session(NS(name="google", url="https://g/",
137
+ channel=None, persistent=False))
138
+ assert "broker_stopped" not in out