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.
- procesio_cli/__init__.py +18 -0
- procesio_cli/_cli.py +71 -0
- procesio_cli/agents/__init__.py +0 -0
- procesio_cli/agents/_lib/__init__.py +0 -0
- procesio_cli/agents/_lib/actiondef.py +24 -0
- procesio_cli/agents/_lib/errors.py +40 -0
- procesio_cli/agents/_lib/reversibility.py +236 -0
- procesio_cli/agents/_lib/toolrunner.py +141 -0
- procesio_cli/agents/connector-builder/CONNECTOR-BUILDER-PLAYBOOK.md +62 -0
- procesio_cli/agents/connector-builder/CONNECTOR-BUILDER-PROCESIO-INTEROP.md +76 -0
- procesio_cli/agents/connector-builder/CONNECTOR-BUILDER-TROUBLESHOOTING.md +60 -0
- procesio_cli/agents/connector-builder/README.md +51 -0
- procesio_cli/agents/connector-builder/agent.yaml +61 -0
- procesio_cli/agents/connector-builder/context.py +19 -0
- procesio_cli/agents/connector-builder/handlers/__init__.py +1 -0
- procesio_cli/agents/connector-builder/handlers/checklist.py +71 -0
- procesio_cli/agents/connector-builder/handlers/guidance.py +37 -0
- procesio_cli/agents/connector-builder/handlers/nextstep.py +221 -0
- procesio_cli/agents/connector-builder/handlers/status.py +35 -0
- procesio_cli/agents/connector-builder/knowledge.py +47 -0
- procesio_cli/agents/connector-builder/main.py +93 -0
- procesio_cli/agents/connector-builder/tests/conftest.py +95 -0
- procesio_cli/agents/connector-builder/tests/test_cba_agent.py +148 -0
- procesio_cli/agents/orchestrator/__init__.py +0 -0
- procesio_cli/agents/orchestrator/bootstraplib.py +166 -0
- procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/00-INDEX.md +60 -0
- procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/01-PROCESSES.md +230 -0
- procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/02-FORMS.md +287 -0
- procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/03-INTEGRATIONS.md +384 -0
- procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/04-DATABASE.md +293 -0
- procesio_cli/agents/procesio/PROCESIO-API-RELIABILITY-DOCTRINE.md +113 -0
- procesio_cli/agents/procesio/PROCESIO-BEST-PRACTICES.md +316 -0
- procesio_cli/agents/procesio/PROCESIO-BUILD-AND-TEST-PLAYBOOK.md +217 -0
- procesio_cli/agents/procesio/PROCESIO-DATASTORE.md +72 -0
- procesio_cli/agents/procesio/PROCESIO-ENVIRONMENTS.md +62 -0
- procesio_cli/agents/procesio/PROCESIO-SCHEDULING.md +47 -0
- procesio_cli/agents/procesio/PROCESIO-VISUAL-ORGANIZATION.md +175 -0
- procesio_cli/agents/procesio/README.md +97 -0
- procesio_cli/agents/procesio/__init__.py +0 -0
- procesio_cli/agents/procesio/agent.yaml +73 -0
- procesio_cli/agents/procesio/audit.py +226 -0
- procesio_cli/agents/procesio/checklist.py +135 -0
- procesio_cli/agents/procesio/context.py +19 -0
- procesio_cli/agents/procesio/handlers/__init__.py +0 -0
- procesio_cli/agents/procesio/handlers/audit.py +39 -0
- procesio_cli/agents/procesio/handlers/checklist.py +34 -0
- procesio_cli/agents/procesio/handlers/guidance.py +36 -0
- procesio_cli/agents/procesio/handlers/status.py +33 -0
- procesio_cli/agents/procesio/handlers/verify.py +39 -0
- procesio_cli/agents/procesio/knowledge.py +115 -0
- procesio_cli/agents/procesio/main.py +89 -0
- procesio_cli/agents/procesio/tests/__init__.py +0 -0
- procesio_cli/agents/procesio/tests/conftest.py +62 -0
- procesio_cli/agents/procesio/tests/test_audit.py +91 -0
- procesio_cli/agents/procesio/tests/test_checklist.py +28 -0
- procesio_cli/agents/procesio/tests/test_guidance.py +78 -0
- procesio_cli/agents/procesio/tests/test_manifest_sync.py +48 -0
- procesio_cli/agents/procesio/tests/test_verify.py +134 -0
- procesio_cli/agents/procesio/tests/test_workspace_scope.py +97 -0
- procesio_cli/agents/procesio/verifylib.py +222 -0
- procesio_cli/dashboard/README.md +117 -0
- procesio_cli/dashboard/__init__.py +18 -0
- procesio_cli/dashboard/serve.py +98 -0
- procesio_cli/dashboard/server/__init__.py +1 -0
- procesio_cli/dashboard/server/config_schemas.py +92 -0
- procesio_cli/dashboard/server/google.py +103 -0
- procesio_cli/dashboard/server/handler.py +160 -0
- procesio_cli/dashboard/server/inventory.py +213 -0
- procesio_cli/dashboard/server/jobs.py +118 -0
- procesio_cli/dashboard/server/llmtest.py +181 -0
- procesio_cli/dashboard/server/procesio_env.py +94 -0
- procesio_cli/dashboard/server/routes.py +74 -0
- procesio_cli/dashboard/server/runner.py +150 -0
- procesio_cli/dashboard/server/security.py +29 -0
- procesio_cli/dashboard/server/setup.py +211 -0
- procesio_cli/dashboard/server/validate.py +152 -0
- procesio_cli/dashboard/tests/conftest.py +16 -0
- procesio_cli/dashboard/tests/test_dashboard.py +225 -0
- procesio_cli/dashboard/tests/test_procesio_env.py +159 -0
- procesio_cli/dashboard/web/actions.js +274 -0
- procesio_cli/dashboard/web/api.js +79 -0
- procesio_cli/dashboard/web/app.js +385 -0
- procesio_cli/dashboard/web/copilot.js +72 -0
- procesio_cli/dashboard/web/google.js +121 -0
- procesio_cli/dashboard/web/index.html +67 -0
- procesio_cli/dashboard/web/procesio_env.js +187 -0
- procesio_cli/dashboard/web/styles.css +207 -0
- procesio_cli/registry.py +370 -0
- procesio_cli/scripts/build-router.py +249 -0
- procesio_cli/scripts/build-tool-skill.py +202 -0
- procesio_cli/scripts/check-requirements.py +131 -0
- procesio_cli/scripts/check-skill-governance.py +174 -0
- procesio_cli/scripts/evaluate-skill-routing.py +217 -0
- procesio_cli/scripts/evaluate-skills.py +316 -0
- procesio_cli/scripts/get-skill.py +122 -0
- procesio_cli/scripts/list-skills.py +68 -0
- procesio_cli/scripts/list-tools.py +73 -0
- procesio_cli/scripts/run-agent.py +59 -0
- procesio_cli/scripts/run-tool.py +123 -0
- procesio_cli/scripts/secret_scan.py +584 -0
- procesio_cli/scripts/set-credential.py +126 -0
- procesio_cli/scripts/validate-skills.py +530 -0
- procesio_cli/skills/PORTFOLIO.md +134 -0
- procesio_cli/skills/__init__.py +6 -0
- procesio_cli/skills/agent-skill-engineer/SKILL.md +226 -0
- procesio_cli/skills/agent-skill-engineer/evals/evals.json +422 -0
- procesio_cli/skills/agent-skill-engineer/references/authoring-standard.md +178 -0
- procesio_cli/skills/agent-skill-engineer/references/decision-framework.md +107 -0
- procesio_cli/skills/agent-skill-engineer/references/domain-evidence-protocol.md +248 -0
- procesio_cli/skills/agent-skill-engineer/references/evaluation-standard.md +191 -0
- procesio_cli/skills/agent-skill-engineer/references/expert-lenses.md +167 -0
- procesio_cli/skills/agent-skill-engineer/references/field-gate-standard.md +231 -0
- procesio_cli/skills/agent-skill-engineer/references/optimization-protocol.md +233 -0
- procesio_cli/skills/agent-skill-engineer/references/optimizer-contract.md +268 -0
- procesio_cli/skills/agent-skill-engineer/references/portability-standard.md +99 -0
- procesio_cli/skills/agent-skill-engineer/references/research-basis.md +128 -0
- procesio_cli/skills/agent-skill-engineer/references/review-standard.md +143 -0
- procesio_cli/skills/agent-skill-engineer/scripts/audit_skill.py +959 -0
- procesio_cli/skills/agent-skill-engineer/scripts/optimize_skill.py +891 -0
- procesio_cli/skills/agent-skill-engineer/scripts/scaffold_skill.py +397 -0
- procesio_cli/skills/evals/baseline-catalog.json +14 -0
- procesio_cli/skills/evals/baseline-routing-v2.json +38 -0
- procesio_cli/skills/evals/baseline.json +37 -0
- procesio_cli/skills/evals/behavioral.json +367 -0
- procesio_cli/skills/evals/field-boundary-development-v1.json +126 -0
- procesio_cli/skills/evals/field-closeout-correction-development-v1.json +23 -0
- procesio_cli/skills/evals/field-closeout-development-v1.json +89 -0
- procesio_cli/skills/evals/portfolio-pressure-training-v1.json +83 -0
- procesio_cli/skills/evals/routing.json +363 -0
- procesio_cli/skills/evals/validation-baseline.json +4 -0
- procesio_cli/skills/procesio-cli/SKILL.md +134 -0
- procesio_cli/skills/procesio-cli/evals/evals.json +111 -0
- procesio_cli/skills/procesio-cli/evals/workflows.json +16 -0
- procesio_cli/skills/procesio-cli/references/connector-lifecycle.md +47 -0
- procesio_cli/skills/procesio-cli/references/credentials-admin.md +113 -0
- procesio_cli/skills/procesio-cli/references/data-verification.md +71 -0
- procesio_cli/skills/procesio-cli/references/documents-files.md +44 -0
- procesio_cli/skills/procesio-cli/references/form-e2e.md +57 -0
- procesio_cli/skills/procesio-cli/references/operation-contract.md +138 -0
- procesio_cli/skills/procesio-cli/references/process-debugging.md +65 -0
- procesio_cli/skills/procesio-cli/references/process-lifecycle.md +88 -0
- procesio_cli/skills/procesio-cli/references/schedules-webhooks.md +58 -0
- procesio_cli/skills/procesio-cli/references/transport-environments.md +53 -0
- procesio_cli/skills/procesio-cli-maintainer/SKILL.md +84 -0
- procesio_cli/skills/procesio-cli-maintainer/evals/evals.json +116 -0
- procesio_cli/skills/procesio-cli-maintainer/references/change-contract.md +34 -0
- procesio_cli/skills/procesio-cli-maintainer/references/mcp-compatibility.md +13 -0
- procesio_cli/skills/procesio-cli-maintainer/references/skill-authoring.md +51 -0
- procesio_cli/skills/procesio-platform-advisor/SKILL.md +82 -0
- procesio_cli/skills/procesio-platform-advisor/evals/evals.json +116 -0
- procesio_cli/skills/procesio-platform-advisor/references/capability-map.md +22 -0
- procesio_cli/skills/procesio-platform-advisor/references/fit-framework.md +35 -0
- procesio_cli/skills/procesio-platform-advisor/references/freshness-policy.md +25 -0
- procesio_cli/skills/procesio-platform-advisor/references/sizing-method.md +70 -0
- procesio_cli/skills/procesio-platform-advisor/scripts/estimate_capacity.py +99 -0
- procesio_cli/skills/procesio-setup/SKILL.md +180 -0
- procesio_cli/skills/sql-server-optimizer/SKILL.md +86 -0
- procesio_cli/skills/sql-server-optimizer/evals/evals.json +116 -0
- procesio_cli/skills/sql-server-optimizer/references/db-context.md +44 -0
- procesio_cli/skills/sql-server-optimizer/references/generic-mode.md +32 -0
- procesio_cli/skills/sql-server-optimizer/references/procesio-mode.md +40 -0
- procesio_cli/skills/sql-server-optimizer/references/sql-rules.md +43 -0
- procesio_cli/skills/sql-server-optimizer/scripts/export-indexes.sql +178 -0
- procesio_cli/skills/sql-server-optimizer/scripts/export-procs-and-functions.sql +118 -0
- procesio_cli/skills/sql-server-optimizer/scripts/export-tables.sql +367 -0
- procesio_cli/skills/tests/__init__.py +0 -0
- procesio_cli/skills/tests/test_agent_skill_engineer.py +240 -0
- procesio_cli/skills/tests/test_auth_failure_stop.py +25 -0
- procesio_cli/skills/tests/test_capacity_estimator.py +85 -0
- procesio_cli/skills/tests/test_field_boundary_learning.py +100 -0
- procesio_cli/skills/tests/test_field_closeout_learning.py +123 -0
- procesio_cli/skills/tests/test_field_gate_standard.py +76 -0
- procesio_cli/skills/tests/test_operational_playbooks.py +51 -0
- procesio_cli/skills/tests/test_portfolio_pressure_training.py +35 -0
- procesio_cli/skills/tests/test_process_lifecycle_single_run.py +25 -0
- procesio_cli/skills/tests/test_skill_evaluator.py +67 -0
- procesio_cli/skills/tests/test_skill_optimizer.py +473 -0
- procesio_cli/skills/tests/test_skill_portfolio_review.py +70 -0
- procesio_cli/skills/tests/test_skill_release_binding.py +204 -0
- procesio_cli/skills/tests/test_skill_routing.py +74 -0
- procesio_cli/skills/tests/test_skill_scaffold_v2.py +116 -0
- procesio_cli/skills/tests/test_validate_skills.py +115 -0
- procesio_cli/tools/__init__.py +0 -0
- procesio_cli/tools/_lib/README.md +119 -0
- procesio_cli/tools/_lib/__init__.py +0 -0
- procesio_cli/tools/_lib/accounting.py +120 -0
- procesio_cli/tools/_lib/contacts.py +544 -0
- procesio_cli/tools/_lib/creds.py +83 -0
- procesio_cli/tools/_lib/creds_backends.py +578 -0
- procesio_cli/tools/_lib/dbprofiles.py +147 -0
- procesio_cli/tools/_lib/dbquery.py +286 -0
- procesio_cli/tools/_lib/dbschema.py +225 -0
- procesio_cli/tools/_lib/io.py +54 -0
- procesio_cli/tools/_lib/manifest.py +297 -0
- procesio_cli/tools/_lib/skill_release.py +127 -0
- procesio_cli/tools/_lib/skill_resources.py +118 -0
- procesio_cli/tools/_lib/userdata.py +228 -0
- procesio_cli/tools/_lib/webserialize/__init__.py +16 -0
- procesio_cli/tools/_lib/webserialize/admin.py +61 -0
- procesio_cli/tools/_lib/webserialize/client.py +264 -0
- procesio_cli/tools/_lib/webserialize/config.py +96 -0
- procesio_cli/tools/_lib/webserialize/errors.py +27 -0
- procesio_cli/tools/_lib/webserialize/framing.py +45 -0
- procesio_cli/tools/_lib/webserialize/registry.py +47 -0
- procesio_cli/tools/_lib/webserialize/runtime.py +61 -0
- procesio_cli/tools/_lib/webserialize/server.py +510 -0
- procesio_cli/tools/_lib/websession.py +194 -0
- procesio_cli/tools/connector-builder/CONNECTOR-BUILDER-API-NOTES.md +91 -0
- procesio_cli/tools/connector-builder/README.md +101 -0
- procesio_cli/tools/connector-builder/SKILL.md +248 -0
- procesio_cli/tools/connector-builder/__init__.py +7 -0
- procesio_cli/tools/connector-builder/actiondef.py +24 -0
- procesio_cli/tools/connector-builder/client.py +251 -0
- procesio_cli/tools/connector-builder/errors.py +44 -0
- procesio_cli/tools/connector-builder/gen_manifest.py +142 -0
- procesio_cli/tools/connector-builder/handlers/__init__.py +1 -0
- procesio_cli/tools/connector-builder/handlers/admin.py +182 -0
- procesio_cli/tools/connector-builder/handlers/auth.py +74 -0
- procesio_cli/tools/connector-builder/handlers/builds.py +396 -0
- procesio_cli/tools/connector-builder/handlers/common.py +104 -0
- procesio_cli/tools/connector-builder/handlers/files.py +111 -0
- procesio_cli/tools/connector-builder/handlers/raw.py +38 -0
- procesio_cli/tools/connector-builder/handlers/telemetry.py +39 -0
- procesio_cli/tools/connector-builder/main.py +94 -0
- procesio_cli/tools/connector-builder/tests/conftest.py +146 -0
- procesio_cli/tools/connector-builder/tests/test_cb_client.py +86 -0
- procesio_cli/tools/connector-builder/tests/test_cb_dispatch.py +105 -0
- procesio_cli/tools/connector-builder/tests/test_cb_manifest_sync.py +76 -0
- procesio_cli/tools/connector-builder/tests/test_cb_wait.py +123 -0
- procesio_cli/tools/connector-builder/tool.yaml +671 -0
- procesio_cli/tools/framework-map/.gitattributes +2 -0
- procesio_cli/tools/framework-map/README.md +98 -0
- procesio_cli/tools/framework-map/SKILL.md +30 -0
- procesio_cli/tools/framework-map/app.js +188 -0
- procesio_cli/tools/framework-map/fm_builder.py +476 -0
- procesio_cli/tools/framework-map/fm_catalog.py +19 -0
- procesio_cli/tools/framework-map/fm_ro_catalog.py +94 -0
- procesio_cli/tools/framework-map/fm_strings.py +101 -0
- procesio_cli/tools/framework-map/main.py +95 -0
- procesio_cli/tools/framework-map/styles.css +214 -0
- procesio_cli/tools/framework-map/tests/conftest.py +33 -0
- procesio_cli/tools/framework-map/tests/test_fm_build.py +126 -0
- procesio_cli/tools/framework-map/tests/test_fm_manifest_sync.py +63 -0
- procesio_cli/tools/framework-map/tests/test_fm_store_tree.py +75 -0
- procesio_cli/tools/framework-map/tool.yaml +61 -0
- procesio_cli/tools/mysql/MOVED-TO-CENTRAL.md +29 -0
- procesio_cli/tools/mysql/README.md +196 -0
- procesio_cli/tools/mysql/SKILL.md +37 -0
- procesio_cli/tools/mysql/__init__.py +0 -0
- procesio_cli/tools/mysql/connection.py +191 -0
- procesio_cli/tools/mysql/main.py +487 -0
- procesio_cli/tools/mysql/profiles.template.json +1 -0
- procesio_cli/tools/mysql/schema.py +434 -0
- procesio_cli/tools/mysql/tests/__init__.py +0 -0
- procesio_cli/tools/mysql/tests/conftest.py +21 -0
- procesio_cli/tools/mysql/tests/test_manifest_sync.py +68 -0
- procesio_cli/tools/mysql/tests/test_mysql.py +201 -0
- procesio_cli/tools/mysql/tests/test_mysql_schema.py +337 -0
- procesio_cli/tools/mysql/tool.yaml +112 -0
- procesio_cli/tools/procesio/DTO-SUBTOOLS-NOTE.md +360 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/00-INDEX.md +67 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/01-ANATOMY.md +209 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/02-CODE-INJECTION.md +309 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/03-DOM-CONTRACT.md +370 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/04-INTERACTION-RECIPES.md +600 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/05-STEPPER-AND-MOTION.md +426 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/06-PROCESS-INTEGRATION.md +347 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/07-DEPLOY-WORKFLOW.md +294 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/08-PITFALLS.md +569 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/09-NAVIGATION-AND-HOSTING.md +308 -0
- procesio_cli/tools/procesio/PHASE4-E2E-NOTES.md +594 -0
- procesio_cli/tools/procesio/PROCESIO-API-CORRECTIONS.md +295 -0
- procesio_cli/tools/procesio/PROCESIO-API-NOTES.md +6976 -0
- procesio_cli/tools/procesio/PROCESIO-AUTH-NOTES.md +226 -0
- procesio_cli/tools/procesio/PROCESIO-CARD-BUILD-NOTES.md +183 -0
- procesio_cli/tools/procesio/PROCESIO-CONNECTORS-NOTES.md +141 -0
- procesio_cli/tools/procesio/PROCESIO-CUSTOM-ACTION-NOTES.md +179 -0
- procesio_cli/tools/procesio/PROCESIO-DOCS-FIX-REPORT.md +123 -0
- procesio_cli/tools/procesio/PROCESIO-ENVIRONMENTS-NOTES.md +94 -0
- procesio_cli/tools/procesio/PROCESIO-FE-VALIDATION-NOTES.md +107 -0
- procesio_cli/tools/procesio/PROCESIO-FOREACH-NOTES.md +199 -0
- procesio_cli/tools/procesio/PROCESIO-FORM-API-HANG-NOTE.md +101 -0
- procesio_cli/tools/procesio/PROCESIO-FORM-SUBMISSION-NOTES.md +172 -0
- procesio_cli/tools/procesio/PROCESIO-HTML-TO-DOCX-NOTES.md +110 -0
- procesio_cli/tools/procesio/PROCESIO-INSTANCE-HISTORY-NOTES.md +242 -0
- procesio_cli/tools/procesio/PROCESIO-METERING-NOTES.md +201 -0
- procesio_cli/tools/procesio/PROCESIO-NODE-CODE-NOTES.md +279 -0
- procesio_cli/tools/procesio/PROCESIO-NODE-MODULE-WHITELIST.md +113 -0
- procesio_cli/tools/procesio/PROCESIO-PYTHON-ACTION-NOTES.md +165 -0
- procesio_cli/tools/procesio/PROCESIO-QUERY-STORE-NOTES.md +826 -0
- procesio_cli/tools/procesio/PROCESIO-RECONCILIATION-PATTERNS.md +104 -0
- procesio_cli/tools/procesio/PROCESIO-RESOURCE-MODEL-NOTES.md +1100 -0
- procesio_cli/tools/procesio/PROCESIO-SEND-EMAIL-CRED-OPTIONALITY.md +45 -0
- procesio_cli/tools/procesio/PROCESIO-SEND-EMAIL-NOTES.md +252 -0
- procesio_cli/tools/procesio/PROCESIO-SQL-ACTIONS-NOTES.md +284 -0
- procesio_cli/tools/procesio/PROCESIO-USAGE-GUIDE.md +219 -0
- procesio_cli/tools/procesio/README.md +341 -0
- procesio_cli/tools/procesio/SCHEDULE-INPUT-SECURITY-NOTES.md +63 -0
- procesio_cli/tools/procesio/SKILL.md +694 -0
- procesio_cli/tools/procesio/__init__.py +1 -0
- procesio_cli/tools/procesio/actiondef.py +27 -0
- procesio_cli/tools/procesio/assets/html2docx/html2docx.js +2155 -0
- procesio_cli/tools/procesio/auth.py +354 -0
- procesio_cli/tools/procesio/autogen.py +121 -0
- procesio_cli/tools/procesio/client.py +355 -0
- procesio_cli/tools/procesio/config.py +96 -0
- procesio_cli/tools/procesio/data/endpoints.json +2901 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/01-authentication.md +180 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/02-conventions.md +116 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/ANONYMOUS-SURFACE.md +51 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/README.md +104 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/SYMBOL-INDEX.md +444 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/03-auth-users-workspaces.md +731 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/04-processes.md +913 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/05-actions.md +605 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/06-files.md +237 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/07-forms-documents.md +985 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/08-credentials.md +532 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/09-datastore-datatypes.md +830 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/10-custom-urls.md +319 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/11-subscriptions-resources-analytics.md +455 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/12-webhooks-notifications-misc.md +519 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/13-realtime-signalr.md +153 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/99-internal-and-other-services.md +52 -0
- procesio_cli/tools/procesio/docs_info/FormBuilder mock.ts +5725 -0
- procesio_cli/tools/procesio/docs_info/Procesio Platform Actions.json +30219 -0
- procesio_cli/tools/procesio/docs_info/form-config-enums.ts +92 -0
- procesio_cli/tools/procesio/docs_info/form-theme.ts +1603 -0
- procesio_cli/tools/procesio/docs_info/process-validation-reference-1.md +2739 -0
- procesio_cli/tools/procesio/dto/__init__.py +13 -0
- procesio_cli/tools/procesio/dto/credential/builder.py +179 -0
- procesio_cli/tools/procesio/dto/credential/config.schema.json +19 -0
- procesio_cli/tools/procesio/dto/credential/description.md +193 -0
- procesio_cli/tools/procesio/dto/credential/fixtures/rest.config.json +11 -0
- procesio_cli/tools/procesio/dto/credential/fixtures/rest.dto.json +28 -0
- procesio_cli/tools/procesio/dto/credential/fixtures/rest.template.json +44 -0
- procesio_cli/tools/procesio/dto/credential/template.dto.json +16 -0
- procesio_cli/tools/procesio/dto/data/_refresh.py +147 -0
- procesio_cli/tools/procesio/dto/data/action_catalog.json +30825 -0
- procesio_cli/tools/procesio/dto/data/action_families.json +55 -0
- procesio_cli/tools/procesio/dto/data/platform_types.json +182 -0
- procesio_cli/tools/procesio/dto/datatype/builder.py +223 -0
- procesio_cli/tools/procesio/dto/datatype/config.schema.json +47 -0
- procesio_cli/tools/procesio/dto/datatype/description.md +85 -0
- procesio_cli/tools/procesio/dto/datatype/fixtures/customer.config.json +41 -0
- procesio_cli/tools/procesio/dto/datatype/fixtures/customer.dto.json +164 -0
- procesio_cli/tools/procesio/dto/datatype/template.dto.json +37 -0
- procesio_cli/tools/procesio/dto/document/builder.py +193 -0
- procesio_cli/tools/procesio/dto/document/config.schema.json +33 -0
- procesio_cli/tools/procesio/dto/document/description.md +124 -0
- procesio_cli/tools/procesio/dto/document/fixtures/invoice.config.json +16 -0
- procesio_cli/tools/procesio/dto/document/fixtures/invoice.dto.json +32 -0
- procesio_cli/tools/procesio/dto/document/template.dto.json +14 -0
- procesio_cli/tools/procesio/dto/form/FORM-STYLING-NOTES.md +142 -0
- procesio_cli/tools/procesio/dto/form/GOLDEN-DRIFT-NOTES.md +72 -0
- procesio_cli/tools/procesio/dto/form/RUN-PROCESS-RESULT-NOTES.md +80 -0
- procesio_cli/tools/procesio/dto/form/addelement.py +277 -0
- procesio_cli/tools/procesio/dto/form/builder.py +1009 -0
- procesio_cli/tools/procesio/dto/form/capture_goldens.py +106 -0
- procesio_cli/tools/procesio/dto/form/code_cipher.py +67 -0
- procesio_cli/tools/procesio/dto/form/config.schema.json +76 -0
- procesio_cli/tools/procesio/dto/form/data_shell.json +1 -0
- procesio_cli/tools/procesio/dto/form/description.md +346 -0
- procesio_cli/tools/procesio/dto/form/elements/approval.json +259 -0
- procesio_cli/tools/procesio/dto/form/elements/assignee.json +137 -0
- procesio_cli/tools/procesio/dto/form/elements/button.json +125 -0
- procesio_cli/tools/procesio/dto/form/elements/chart.json +341 -0
- procesio_cli/tools/procesio/dto/form/elements/chat.json +199 -0
- procesio_cli/tools/procesio/dto/form/elements/checkbox.json +153 -0
- procesio_cli/tools/procesio/dto/form/elements/column.json +77 -0
- procesio_cli/tools/procesio/dto/form/elements/columns.json +78 -0
- procesio_cli/tools/procesio/dto/form/elements/datetime-input.json +304 -0
- procesio_cli/tools/procesio/dto/form/elements/divider.json +54 -0
- procesio_cli/tools/procesio/dto/form/elements/dropdown.json +130 -0
- procesio_cli/tools/procesio/dto/form/elements/dynamic-table-row.json +253 -0
- procesio_cli/tools/procesio/dto/form/elements/file-upload.json +196 -0
- procesio_cli/tools/procesio/dto/form/elements/file-viewer.json +169 -0
- procesio_cli/tools/procesio/dto/form/elements/heading.json +79 -0
- procesio_cli/tools/procesio/dto/form/elements/icon.json +107 -0
- procesio_cli/tools/procesio/dto/form/elements/image.json +174 -0
- procesio_cli/tools/procesio/dto/form/elements/input.json +206 -0
- procesio_cli/tools/procesio/dto/form/elements/list.json +202 -0
- procesio_cli/tools/procesio/dto/form/elements/number-input.json +202 -0
- procesio_cli/tools/procesio/dto/form/elements/paragraph.json +79 -0
- procesio_cli/tools/procesio/dto/form/elements/radiobox.json +174 -0
- procesio_cli/tools/procesio/dto/form/elements/section.json +114 -0
- procesio_cli/tools/procesio/dto/form/elements/select.json +217 -0
- procesio_cli/tools/procesio/dto/form/elements/side-panel.json +146 -0
- procesio_cli/tools/procesio/dto/form/elements/signature-pad.json +141 -0
- procesio_cli/tools/procesio/dto/form/elements/static-table-row.json +84 -0
- procesio_cli/tools/procesio/dto/form/elements/step.json +105 -0
- procesio_cli/tools/procesio/dto/form/elements/stepper.json +126 -0
- procesio_cli/tools/procesio/dto/form/elements/tab.json +77 -0
- procesio_cli/tools/procesio/dto/form/elements/table.json +279 -0
- procesio_cli/tools/procesio/dto/form/elements/tabs.json +114 -0
- procesio_cli/tools/procesio/dto/form/elements/textarea.json +213 -0
- procesio_cli/tools/procesio/dto/form/enum_map.json +68 -0
- procesio_cli/tools/procesio/dto/form/fieldpath.py +284 -0
- procesio_cli/tools/procesio/dto/form/fixtures/reg.config.json +32 -0
- procesio_cli/tools/procesio/dto/form/fixtures/reg.elements.json +638 -0
- procesio_cli/tools/procesio/dto/form/sync_from_mock.py +386 -0
- procesio_cli/tools/procesio/dto/framework.py +125 -0
- procesio_cli/tools/procesio/dto/process/builder.py +1991 -0
- procesio_cli/tools/procesio/dto/process/config.schema.json +159 -0
- procesio_cli/tools/procesio/dto/process/description.md +218 -0
- procesio_cli/tools/procesio/dto/process/fixtures/greet.config.json +32 -0
- procesio_cli/tools/procesio/dto/process/fixtures/greet.dto.json +317 -0
- procesio_cli/tools/procesio/dto/process/naming.py +305 -0
- procesio_cli/tools/procesio/dto/process/normalize.py +74 -0
- procesio_cli/tools/procesio/dto/process/template.dto.json +32 -0
- procesio_cli/tools/procesio/dto/refdata.py +87 -0
- procesio_cli/tools/procesio/dto/registry.py +27 -0
- procesio_cli/tools/procesio/dto/webhook/builder.py +142 -0
- procesio_cli/tools/procesio/dto/webhook/config.schema.json +25 -0
- procesio_cli/tools/procesio/dto/webhook/description.md +92 -0
- procesio_cli/tools/procesio/dto/webhook/fixtures/order.config.json +10 -0
- procesio_cli/tools/procesio/dto/webhook/fixtures/order.dto.json +25 -0
- procesio_cli/tools/procesio/dto/webhook/template.dto.json +14 -0
- procesio_cli/tools/procesio/environments.py +264 -0
- procesio_cli/tools/procesio/errors.py +166 -0
- procesio_cli/tools/procesio/flowmodel/README.md +37 -0
- procesio_cli/tools/procesio/flowmodel/__init__.py +14 -0
- procesio_cli/tools/procesio/flowmodel/digest.py +223 -0
- procesio_cli/tools/procesio/flowmodel/families.py +34 -0
- procesio_cli/tools/procesio/flowmodel/fevalidation.py +1098 -0
- procesio_cli/tools/procesio/flowmodel/formdigest.py +232 -0
- procesio_cli/tools/procesio/flowmodel/inspect.py +78 -0
- procesio_cli/tools/procesio/flowmodel/model.py +82 -0
- procesio_cli/tools/procesio/flowmodel/nodeparam.py +871 -0
- procesio_cli/tools/procesio/flowmodel/reader.py +191 -0
- procesio_cli/tools/procesio/flowmodel/sqlparam.py +410 -0
- procesio_cli/tools/procesio/form_code_keys.py +50 -0
- procesio_cli/tools/procesio/formlint.py +292 -0
- procesio_cli/tools/procesio/gen_manifest.py +118 -0
- procesio_cli/tools/procesio/handlers/__init__.py +1 -0
- procesio_cli/tools/procesio/handlers/auth_actions.py +103 -0
- procesio_cli/tools/procesio/handlers/catalog.py +147 -0
- procesio_cli/tools/procesio/handlers/common.py +90 -0
- procesio_cli/tools/procesio/handlers/customaction_ops.py +146 -0
- procesio_cli/tools/procesio/handlers/datastore_ops.py +482 -0
- procesio_cli/tools/procesio/handlers/datatype_ops.py +275 -0
- procesio_cli/tools/procesio/handlers/dto_actions.py +258 -0
- procesio_cli/tools/procesio/handlers/environment_admin.py +146 -0
- procesio_cli/tools/procesio/handlers/fevalidate.py +236 -0
- procesio_cli/tools/procesio/handlers/files.py +141 -0
- procesio_cli/tools/procesio/handlers/flowgraph.py +229 -0
- procesio_cli/tools/procesio/handlers/flowlint.py +269 -0
- procesio_cli/tools/procesio/handlers/form_chains.py +336 -0
- procesio_cli/tools/procesio/handlers/form_code.py +277 -0
- procesio_cli/tools/procesio/handlers/form_element.py +199 -0
- procesio_cli/tools/procesio/handlers/form_events.py +441 -0
- procesio_cli/tools/procesio/handlers/form_update.py +270 -0
- procesio_cli/tools/procesio/handlers/formprocess.py +211 -0
- procesio_cli/tools/procesio/handlers/generic.py +135 -0
- procesio_cli/tools/procesio/handlers/layout.py +137 -0
- procesio_cli/tools/procesio/handlers/nodeparams.py +1018 -0
- procesio_cli/tools/procesio/handlers/process_layout.py +189 -0
- procesio_cli/tools/procesio/handlers/process_naming.py +213 -0
- procesio_cli/tools/procesio/handlers/processes.py +416 -0
- procesio_cli/tools/procesio/handlers/profile_admin.py +184 -0
- procesio_cli/tools/procesio/handlers/resource_ops.py +447 -0
- procesio_cli/tools/procesio/handlers/schedules.py +320 -0
- procesio_cli/tools/procesio/handlers/sqlactions.py +232 -0
- procesio_cli/tools/procesio/handlers/transport.py +463 -0
- procesio_cli/tools/procesio/handlers/usageguide.py +222 -0
- procesio_cli/tools/procesio/layout/README.md +196 -0
- procesio_cli/tools/procesio/layout/__init__.py +11 -0
- procesio_cli/tools/procesio/layout/adapter.py +736 -0
- procesio_cli/tools/procesio/layout/cycles.py +186 -0
- procesio_cli/tools/procesio/layout/dispatch.py +39 -0
- procesio_cli/tools/procesio/layout/elk/elk_runner.mjs +50 -0
- procesio_cli/tools/procesio/layout/elk/package-lock.json +21 -0
- procesio_cli/tools/procesio/layout/elk/package.json +11 -0
- procesio_cli/tools/procesio/layout/elk_engine.py +568 -0
- procesio_cli/tools/procesio/layout/engine.py +1311 -0
- procesio_cli/tools/procesio/layout/report.py +187 -0
- procesio_cli/tools/procesio/main.py +179 -0
- procesio_cli/tools/procesio/profiles.py +193 -0
- procesio_cli/tools/procesio/reliability.py +193 -0
- procesio_cli/tools/procesio/sqlformat.py +167 -0
- procesio_cli/tools/procesio/swagger.py +51 -0
- procesio_cli/tools/procesio/tests/__init__.py +0 -0
- procesio_cli/tools/procesio/tests/conftest.py +129 -0
- procesio_cli/tools/procesio/tests/test_auth.py +200 -0
- procesio_cli/tools/procesio/tests/test_autogen.py +78 -0
- procesio_cli/tools/procesio/tests/test_builder_attrpath_sqlbind.py +180 -0
- procesio_cli/tools/procesio/tests/test_builder_custom_action_catalog.py +72 -0
- procesio_cli/tools/procesio/tests/test_client.py +114 -0
- procesio_cli/tools/procesio/tests/test_client_reliability.py +139 -0
- procesio_cli/tools/procesio/tests/test_customaction.py +103 -0
- procesio_cli/tools/procesio/tests/test_customaction_test.py +80 -0
- procesio_cli/tools/procesio/tests/test_cycles.py +69 -0
- procesio_cli/tools/procesio/tests/test_datastore.py +378 -0
- procesio_cli/tools/procesio/tests/test_datastore_node.py +94 -0
- procesio_cli/tools/procesio/tests/test_dispatch.py +170 -0
- procesio_cli/tools/procesio/tests/test_document_page_size.py +19 -0
- procesio_cli/tools/procesio/tests/test_dto.py +734 -0
- procesio_cli/tools/procesio/tests/test_edit_dryrun_preview.py +96 -0
- procesio_cli/tools/procesio/tests/test_elk_layout.py +221 -0
- procesio_cli/tools/procesio/tests/test_environments.py +214 -0
- procesio_cli/tools/procesio/tests/test_fevalidate_gate.py +104 -0
- procesio_cli/tools/procesio/tests/test_fevalidation.py +317 -0
- procesio_cli/tools/procesio/tests/test_fieldpath_variables.py +87 -0
- procesio_cli/tools/procesio/tests/test_files.py +72 -0
- procesio_cli/tools/procesio/tests/test_flow_digest.py +202 -0
- procesio_cli/tools/procesio/tests/test_flowlint.py +114 -0
- procesio_cli/tools/procesio/tests/test_flowmodel.py +158 -0
- procesio_cli/tools/procesio/tests/test_form_add_element.py +256 -0
- procesio_cli/tools/procesio/tests/test_form_approval_gaps.py +319 -0
- procesio_cli/tools/procesio/tests/test_form_auto_names.py +60 -0
- procesio_cli/tools/procesio/tests/test_form_chains.py +217 -0
- procesio_cli/tools/procesio/tests/test_form_code_actions.py +188 -0
- procesio_cli/tools/procesio/tests/test_form_code_keys.py +92 -0
- procesio_cli/tools/procesio/tests/test_form_code_style.py +178 -0
- procesio_cli/tools/procesio/tests/test_form_delete_element.py +99 -0
- procesio_cli/tools/procesio/tests/test_form_element_config.py +141 -0
- procesio_cli/tools/procesio/tests/test_form_event_maps.py +135 -0
- procesio_cli/tools/procesio/tests/test_form_event_ops.py +376 -0
- procesio_cli/tools/procesio/tests/test_form_event_replace.py +86 -0
- procesio_cli/tools/procesio/tests/test_form_events.py +92 -0
- procesio_cli/tools/procesio/tests/test_form_parity.py +171 -0
- procesio_cli/tools/procesio/tests/test_form_select_source.py +74 -0
- procesio_cli/tools/procesio/tests/test_form_sync.py +35 -0
- procesio_cli/tools/procesio/tests/test_form_update.py +133 -0
- procesio_cli/tools/procesio/tests/test_formlint.py +155 -0
- procesio_cli/tools/procesio/tests/test_formlint_css_scope.py +38 -0
- procesio_cli/tools/procesio/tests/test_formlint_field_names.py +83 -0
- procesio_cli/tools/procesio/tests/test_guards.py +110 -0
- procesio_cli/tools/procesio/tests/test_hidden_setting_types.py +39 -0
- procesio_cli/tools/procesio/tests/test_html2docx_asset.py +132 -0
- procesio_cli/tools/procesio/tests/test_key_handle_terminology.py +45 -0
- procesio_cli/tools/procesio/tests/test_layout.py +574 -0
- procesio_cli/tools/procesio/tests/test_layout_report.py +88 -0
- procesio_cli/tools/procesio/tests/test_manifest_sync.py +68 -0
- procesio_cli/tools/procesio/tests/test_nodedelete.py +151 -0
- procesio_cli/tools/procesio/tests/test_nodeparam.py +826 -0
- procesio_cli/tools/procesio/tests/test_normalize.py +70 -0
- procesio_cli/tools/procesio/tests/test_payload_docs.py +86 -0
- procesio_cli/tools/procesio/tests/test_process_action_naming.py +170 -0
- procesio_cli/tools/procesio/tests/test_process_call_api_seed.py +46 -0
- procesio_cli/tools/procesio/tests/test_process_ext.py +373 -0
- procesio_cli/tools/procesio/tests/test_process_invariants.py +183 -0
- procesio_cli/tools/procesio/tests/test_process_layout.py +117 -0
- procesio_cli/tools/procesio/tests/test_process_naming.py +188 -0
- procesio_cli/tools/procesio/tests/test_process_query_store.py +172 -0
- procesio_cli/tools/procesio/tests/test_processinfo_variable.py +56 -0
- procesio_cli/tools/procesio/tests/test_profiles.py +127 -0
- procesio_cli/tools/procesio/tests/test_put_projects.py +41 -0
- procesio_cli/tools/procesio/tests/test_reliability.py +107 -0
- procesio_cli/tools/procesio/tests/test_removal_gate.py +95 -0
- procesio_cli/tools/procesio/tests/test_resource_ops.py +173 -0
- procesio_cli/tools/procesio/tests/test_save_validity.py +207 -0
- procesio_cli/tools/procesio/tests/test_schedule_cron_shape.py +111 -0
- procesio_cli/tools/procesio/tests/test_schedules.py +309 -0
- procesio_cli/tools/procesio/tests/test_sqlconvert.py +234 -0
- procesio_cli/tools/procesio/tests/test_sqlformat.py +83 -0
- procesio_cli/tools/procesio/tests/test_sqlparam.py +187 -0
- procesio_cli/tools/procesio/tests/test_superseded_actions.py +54 -0
- procesio_cli/tools/procesio/tests/test_surgical_concurrency.py +156 -0
- procesio_cli/tools/procesio/tests/test_tier4.py +123 -0
- procesio_cli/tools/procesio/tests/test_transport.py +147 -0
- procesio_cli/tools/procesio/tests/test_transport_data_stores.py +168 -0
- procesio_cli/tools/procesio/tests/test_transport_mapper_repair.py +150 -0
- procesio_cli/tools/procesio/tests/test_transport_webhook_strip.py +253 -0
- procesio_cli/tools/procesio/tests/test_usage_guide.py +96 -0
- procesio_cli/tools/procesio/tool.yaml +12486 -0
- procesio_cli/tools/sqlserver/MOVED-TO-CENTRAL.md +29 -0
- procesio_cli/tools/sqlserver/README.md +192 -0
- procesio_cli/tools/sqlserver/SKILL.md +37 -0
- procesio_cli/tools/sqlserver/SQLSERVER-SCHEMA-NOTES.md +284 -0
- procesio_cli/tools/sqlserver/__init__.py +0 -0
- procesio_cli/tools/sqlserver/connection.py +242 -0
- procesio_cli/tools/sqlserver/main.py +521 -0
- procesio_cli/tools/sqlserver/profiles.template.json +1 -0
- procesio_cli/tools/sqlserver/schema.py +600 -0
- procesio_cli/tools/sqlserver/tests/__init__.py +0 -0
- procesio_cli/tools/sqlserver/tests/conftest.py +21 -0
- procesio_cli/tools/sqlserver/tests/test_connection.py +75 -0
- procesio_cli/tools/sqlserver/tests/test_dbprofiles.py +92 -0
- procesio_cli/tools/sqlserver/tests/test_dbquery.py +220 -0
- procesio_cli/tools/sqlserver/tests/test_manifest_sync.py +68 -0
- procesio_cli/tools/sqlserver/tests/test_sqlserver.py +326 -0
- procesio_cli/tools/sqlserver/tests/test_sqlserver_schema.py +488 -0
- procesio_cli/tools/sqlserver/tool.yaml +123 -0
- procesio_cli/tools/web/README.md +381 -0
- procesio_cli/tools/web/SKILL.md +37 -0
- procesio_cli/tools/web/WEB-AUTOMATION-NOTES.md +277 -0
- procesio_cli/tools/web/__init__.py +21 -0
- procesio_cli/tools/web/actiondef.py +24 -0
- procesio_cli/tools/web/api.py +444 -0
- procesio_cli/tools/web/brokered.py +107 -0
- procesio_cli/tools/web/driver.py +839 -0
- procesio_cli/tools/web/drivercontract.py +44 -0
- procesio_cli/tools/web/errors.py +54 -0
- procesio_cli/tools/web/handlers/__init__.py +1 -0
- procesio_cli/tools/web/handlers/archive.py +367 -0
- procesio_cli/tools/web/handlers/browse.py +182 -0
- procesio_cli/tools/web/handlers/contacts.py +74 -0
- procesio_cli/tools/web/handlers/sessmgmt.py +120 -0
- procesio_cli/tools/web/main.py +128 -0
- procesio_cli/tools/web/sessions.py +253 -0
- procesio_cli/tools/web/steps.py +162 -0
- procesio_cli/tools/web/tests/__init__.py +0 -0
- procesio_cli/tools/web/tests/conftest.py +197 -0
- procesio_cli/tools/web/tests/test_api.py +330 -0
- procesio_cli/tools/web/tests/test_archive.py +190 -0
- procesio_cli/tools/web/tests/test_brokered.py +138 -0
- procesio_cli/tools/web/tests/test_dispatch.py +132 -0
- procesio_cli/tools/web/tests/test_errors.py +60 -0
- procesio_cli/tools/web/tests/test_manifest_sync.py +76 -0
- procesio_cli/tools/web/tests/test_page_contacts.py +68 -0
- procesio_cli/tools/web/tests/test_sessions.py +145 -0
- procesio_cli/tools/web/tests/test_steps.py +210 -0
- procesio_cli/tools/web/tool.yaml +184 -0
- procesio_cli/tools/xlsx/README.md +34 -0
- procesio_cli/tools/xlsx/SKILL.md +28 -0
- procesio_cli/tools/xlsx/__init__.py +0 -0
- procesio_cli/tools/xlsx/main.py +129 -0
- procesio_cli/tools/xlsx/reader.py +91 -0
- procesio_cli/tools/xlsx/tests/__init__.py +0 -0
- procesio_cli/tools/xlsx/tests/conftest.py +39 -0
- procesio_cli/tools/xlsx/tests/test_xlsx.py +103 -0
- procesio_cli/tools/xlsx/tool.yaml +30 -0
- procesio_cli/webplatform/aat_mcp/AAT-MCP-NOTES.md +244 -0
- procesio_cli/webplatform/aat_mcp/README.md +78 -0
- procesio_cli/webplatform/aat_mcp/bridge.py +705 -0
- procesio_cli/webplatform/aat_mcp/chat_server.py +194 -0
- procesio_cli/webplatform/aat_mcp/chat_surface.snapshot.json +668 -0
- procesio_cli/webplatform/aat_mcp/chat_surface.yaml +372 -0
- procesio_cli/webplatform/aat_mcp/gate.py +68 -0
- procesio_cli/webplatform/aat_mcp/http_server.py +139 -0
- procesio_cli/webplatform/aat_mcp/protocol.py +175 -0
- procesio_cli/webplatform/aat_mcp/server.py +306 -0
- procesio_cli/webplatform/aat_mcp/tests/conftest.py +8 -0
- procesio_cli/webplatform/aat_mcp/tests/test_aat_mcp.py +255 -0
- procesio_cli/webplatform/aat_mcp/tests/test_chat_surface.py +247 -0
- procesio_cli/webplatform/aat_mcp/tests/test_discovery.py +489 -0
- procesio_cli/webplatform/aat_mcp/tests/test_multiuser.py +86 -0
- procesio_cli/webplatform/aat_mcp/tests/test_progressive_discovery.py +89 -0
- procesio_cli/webplatform/aat_mcp/tests/test_protocol.py +180 -0
- procesio_cli/webplatform/aat_mcp/tests/test_skill_discovery.py +23 -0
- procesio_cli-0.1.1.dist-info/METADATA +467 -0
- procesio_cli-0.1.1.dist-info/RECORD +647 -0
- procesio_cli-0.1.1.dist-info/WHEEL +4 -0
- procesio_cli-0.1.1.dist-info/entry_points.txt +7 -0
- procesio_cli-0.1.1.dist-info/licenses/LICENSE +201 -0
- procesio_cli-0.1.1.dist-info/licenses/NOTICE +5 -0
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
"""Public Python API for the web tool.
|
|
2
|
+
|
|
3
|
+
Other tools (e.g. the forthcoming ``whatsapp-personal`` tool) and the outreach
|
|
4
|
+
agent should drive saved sessions through THIS module rather than shelling out
|
|
5
|
+
to the CLI. Everything here is importable as::
|
|
6
|
+
|
|
7
|
+
from tools.web import open_session, run_steps, get_text, screenshot
|
|
8
|
+
# or, for the lower-level pieces:
|
|
9
|
+
from tools.web.api import save_session, list_sessions, delete_session
|
|
10
|
+
|
|
11
|
+
Design
|
|
12
|
+
------
|
|
13
|
+
* ``open_session(name, ...)`` is the workhorse: it loads a saved session's
|
|
14
|
+
storageState and returns a *started* ``PlaywrightDriver``. Use it as a context
|
|
15
|
+
manager so the browser is always torn down::
|
|
16
|
+
|
|
17
|
+
from tools.web import open_session
|
|
18
|
+
with open_session("whatsapp") as d:
|
|
19
|
+
d.goto("https://web.whatsapp.com")
|
|
20
|
+
d.click("div[title='Search']")
|
|
21
|
+
...
|
|
22
|
+
|
|
23
|
+
* ``run_steps(name, steps, url=...)`` runs a declarative step list (see
|
|
24
|
+
``steps.py``) end-to-end against a saved session and returns the collected
|
|
25
|
+
JSON-able outputs - convenient for one-shot scripted interactions.
|
|
26
|
+
|
|
27
|
+
* ``get_text`` / ``screenshot`` are thin one-call conveniences.
|
|
28
|
+
|
|
29
|
+
* ``save_session`` is the interactive capture (headed browser + human signal);
|
|
30
|
+
the ``wait_for_signal`` callback is injectable so callers/tests control when
|
|
31
|
+
the state is captured.
|
|
32
|
+
|
|
33
|
+
All functions accept ``driver_factory`` so tests can inject a FakeDriver and run
|
|
34
|
+
without a real browser; production defaults to ``PlaywrightDriver``.
|
|
35
|
+
"""
|
|
36
|
+
from __future__ import annotations
|
|
37
|
+
|
|
38
|
+
from typing import Any, Callable
|
|
39
|
+
|
|
40
|
+
from tools.web import sessions
|
|
41
|
+
from tools.web.driver import BrowserDriver, PlaywrightDriver
|
|
42
|
+
from tools.web.errors import UsageError
|
|
43
|
+
from tools.web.steps import run_steps as _interpret_steps
|
|
44
|
+
|
|
45
|
+
# Re-export the metadata-only helpers so callers get one import surface.
|
|
46
|
+
session_path = sessions.session_path
|
|
47
|
+
list_sessions = sessions.list_all
|
|
48
|
+
delete_session = sessions.delete
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _default_factory(*, storage_state=None, headless=True, channel=None,
|
|
52
|
+
user_data_dir=None, extra_args=None):
|
|
53
|
+
return PlaywrightDriver(storage_state=storage_state, headless=headless,
|
|
54
|
+
channel=channel, user_data_dir=user_data_dir,
|
|
55
|
+
extra_args=extra_args)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def open_session(name: str, *, headless: bool = True, channel: str | None = None,
|
|
59
|
+
url: str | None = None, user_data_dir: str | None = None,
|
|
60
|
+
driver_factory: Callable = _default_factory,
|
|
61
|
+
extra_args: list | None = None) -> BrowserDriver:
|
|
62
|
+
"""Load a saved session and return a STARTED driver (use as a context mgr).
|
|
63
|
+
|
|
64
|
+
Two modes: a storageState session (default) OR a PERSISTENT profile (for
|
|
65
|
+
IndexedDB-auth sites like WhatsApp Web, or anti-bot-sensitive sites like
|
|
66
|
+
Google — the on-disk profile carries the login, no storageState involved).
|
|
67
|
+
The persistent mode is selected when ``user_data_dir`` is passed explicitly OR
|
|
68
|
+
auto-detected when a ``<name>.profile`` directory exists for the session, so
|
|
69
|
+
the CLI run/get-text/screenshot actions transparently use whichever mode the
|
|
70
|
+
session was saved in. Raises SessionError if a storageState session is
|
|
71
|
+
missing. Navigates to ``url`` first.
|
|
72
|
+
"""
|
|
73
|
+
# Auto-detect a persistent profile saved via `save-session --persistent`:
|
|
74
|
+
# prefer it over storageState so a profile session is usable, not write-only.
|
|
75
|
+
if user_data_dir is None and sessions.profile_exists(name):
|
|
76
|
+
user_data_dir = str(sessions.profile_dir(name))
|
|
77
|
+
if user_data_dir is not None:
|
|
78
|
+
driver = driver_factory(storage_state=None, headless=headless,
|
|
79
|
+
channel=channel, user_data_dir=user_data_dir,
|
|
80
|
+
extra_args=extra_args)
|
|
81
|
+
else:
|
|
82
|
+
state = sessions.load_state(name)
|
|
83
|
+
driver = driver_factory(storage_state=state, headless=headless, channel=channel,
|
|
84
|
+
extra_args=extra_args)
|
|
85
|
+
driver.start()
|
|
86
|
+
# Persistent profiles drop SESSION-scoped cookies on close (Chromium never
|
|
87
|
+
# writes them to disk), so a cookie-auth site (e.g. Ryver) reopens logged
|
|
88
|
+
# out. If save-session captured a cookie sidecar, replay it into the fresh
|
|
89
|
+
# context BEFORE navigating so the very first request carries the session.
|
|
90
|
+
if user_data_dir is not None and sessions.cookies_exist(name):
|
|
91
|
+
inject = getattr(driver, "add_cookies", None)
|
|
92
|
+
cookies = sessions.load_cookies(name)
|
|
93
|
+
if cookies and callable(inject):
|
|
94
|
+
inject(cookies)
|
|
95
|
+
if url:
|
|
96
|
+
driver.goto(url)
|
|
97
|
+
return driver
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def run_steps(name: str, steps: list[dict], *, url: str | None = None,
|
|
101
|
+
headless: bool = True, channel: str | None = None,
|
|
102
|
+
user_data_dir: str | None = None,
|
|
103
|
+
hold_seconds: int | None = None,
|
|
104
|
+
hold_until_selector: str | None = None,
|
|
105
|
+
hold_until_url_excludes: str | None = None,
|
|
106
|
+
driver_factory: Callable = _default_factory) -> dict:
|
|
107
|
+
"""Run a declarative step list against a saved session; return collected
|
|
108
|
+
outputs ``{"session", "results", "screenshots", "final_url"}``.
|
|
109
|
+
|
|
110
|
+
If ``url`` is given it is visited first (equivalent to a leading goto step).
|
|
111
|
+
``user_data_dir`` selects the persistent-profile mode. The driver is always
|
|
112
|
+
closed before returning.
|
|
113
|
+
|
|
114
|
+
``hold_seconds`` keeps the HEADED browser open for up to that long after the
|
|
115
|
+
last step, so a human can review what was staged and click the irreversible
|
|
116
|
+
control themselves - the agent never presses Submit. ``hold_until_selector``
|
|
117
|
+
/ ``hold_until_url_excludes`` end the hold early once the human has acted.
|
|
118
|
+
A hold that runs out is SUCCESS, not failure: the steps still ran, so the
|
|
119
|
+
result carries ``hold.completed = False`` rather than raising. Adds a
|
|
120
|
+
``hold`` block to the output; ``final_url`` and ``diagnostics`` are read
|
|
121
|
+
AFTER the hold so they reflect what the human did.
|
|
122
|
+
"""
|
|
123
|
+
if hold_seconds is not None and hold_seconds <= 0:
|
|
124
|
+
raise UsageError("--hold-seconds must be a positive number of seconds")
|
|
125
|
+
if hold_seconds is not None and headless:
|
|
126
|
+
raise UsageError("--hold-seconds requires --headed: holding a headless "
|
|
127
|
+
"browser open gives the human nothing to act on")
|
|
128
|
+
if hold_seconds is None and (hold_until_selector or hold_until_url_excludes):
|
|
129
|
+
raise UsageError("--hold-until-selector/--hold-until-url-excludes require "
|
|
130
|
+
"--hold-seconds")
|
|
131
|
+
driver = open_session(name, headless=headless, channel=channel, url=url,
|
|
132
|
+
user_data_dir=user_data_dir, driver_factory=driver_factory)
|
|
133
|
+
try:
|
|
134
|
+
out = _interpret_steps(driver, steps)
|
|
135
|
+
if hold_seconds is not None:
|
|
136
|
+
out["hold"] = _run_hold(driver, hold_seconds, hold_until_selector,
|
|
137
|
+
hold_until_url_excludes)
|
|
138
|
+
# Re-read AFTER the hold: the whole point is what the human did.
|
|
139
|
+
final = _safe_url(driver)
|
|
140
|
+
if final is not None:
|
|
141
|
+
out["final_url"] = final
|
|
142
|
+
out["diagnostics"] = _diagnostics(driver)
|
|
143
|
+
finally:
|
|
144
|
+
_safe_close(driver)
|
|
145
|
+
out["session"] = name
|
|
146
|
+
return out
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def get_text(name: str, url: str, *, selector: str | None = None,
|
|
150
|
+
wait: str | None = None, headless: bool = True,
|
|
151
|
+
channel: str | None = None,
|
|
152
|
+
driver_factory: Callable = _default_factory) -> dict:
|
|
153
|
+
"""Load a session, navigate to ``url``, return visible text.
|
|
154
|
+
|
|
155
|
+
With ``selector`` returns that element's text; otherwise the whole page body.
|
|
156
|
+
``wait`` (a selector) is awaited before reading - handy for SPA content.
|
|
157
|
+
Returns ``{"session", "url", "selector", "text", "final_url"}``.
|
|
158
|
+
"""
|
|
159
|
+
driver = open_session(name, headless=headless, channel=channel, url=url,
|
|
160
|
+
driver_factory=driver_factory)
|
|
161
|
+
try:
|
|
162
|
+
if wait:
|
|
163
|
+
driver.wait_for(wait)
|
|
164
|
+
text = driver.extract_text(selector)
|
|
165
|
+
final = _safe_url(driver)
|
|
166
|
+
diag = _diagnostics(driver)
|
|
167
|
+
finally:
|
|
168
|
+
_safe_close(driver)
|
|
169
|
+
return {"session": name, "url": url, "selector": selector,
|
|
170
|
+
"text": text, "final_url": final, "diagnostics": diag}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def screenshot(name: str, url: str, out: str, *, full_page: bool = True,
|
|
174
|
+
wait: str | None = None, headless: bool = True,
|
|
175
|
+
channel: str | None = None,
|
|
176
|
+
driver_factory: Callable = _default_factory) -> dict:
|
|
177
|
+
"""Load a session, navigate to ``url``, save a screenshot to ``out``.
|
|
178
|
+
|
|
179
|
+
Returns ``{"session", "url", "path", "final_url"}``.
|
|
180
|
+
"""
|
|
181
|
+
driver = open_session(name, headless=headless, channel=channel, url=url,
|
|
182
|
+
driver_factory=driver_factory)
|
|
183
|
+
try:
|
|
184
|
+
if wait:
|
|
185
|
+
driver.wait_for(wait)
|
|
186
|
+
path = driver.screenshot(out, full_page=full_page)
|
|
187
|
+
final = _safe_url(driver)
|
|
188
|
+
diag = _diagnostics(driver)
|
|
189
|
+
finally:
|
|
190
|
+
_safe_close(driver)
|
|
191
|
+
return {"session": name, "url": url, "path": path, "final_url": final, "diagnostics": diag}
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def render_pdf(html: str, out: str, *, fmt: str = "A4",
|
|
195
|
+
width: str | None = None, height: str | None = None,
|
|
196
|
+
margin: str | None = None,
|
|
197
|
+
driver_factory: Callable = _default_factory) -> dict:
|
|
198
|
+
"""Render an HTML string to a PDF file — no session, no navigation.
|
|
199
|
+
|
|
200
|
+
Launches a throwaway headless Chromium (Chromium's ``page.pdf()`` is
|
|
201
|
+
headless-only), sets the page content to ``html``, writes the PDF to ``out``,
|
|
202
|
+
and tears the browser down. Reusable HTML→PDF for deterministic document
|
|
203
|
+
generation (e.g. the invoice-collector reconstructing a Ryver invoice).
|
|
204
|
+
``width`` + ``height`` give a custom sheet (e.g. a 1000mm x 2000mm roll-up)
|
|
205
|
+
instead of ``fmt``; ``margin`` overrides the default document margins.
|
|
206
|
+
Returns ``{"out": path, "bytes": n}``.
|
|
207
|
+
"""
|
|
208
|
+
import os
|
|
209
|
+
|
|
210
|
+
driver = driver_factory(storage_state=None, headless=True)
|
|
211
|
+
driver.start()
|
|
212
|
+
try:
|
|
213
|
+
driver.render_pdf(html, out, fmt=fmt, width=width, height=height, margin=margin)
|
|
214
|
+
finally:
|
|
215
|
+
_safe_close(driver)
|
|
216
|
+
try:
|
|
217
|
+
size = os.path.getsize(out)
|
|
218
|
+
except OSError:
|
|
219
|
+
size = 0
|
|
220
|
+
return {"out": out, "bytes": size}
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def save_session(name: str, url: str, *,
|
|
224
|
+
wait_for_signal: Callable[[], Any] | None = None,
|
|
225
|
+
channel: str | None = None, persistent: bool = False,
|
|
226
|
+
wait_seconds: int | None = None,
|
|
227
|
+
wait_until_url_excludes: str | None = None,
|
|
228
|
+
driver_factory: Callable = _default_factory) -> dict:
|
|
229
|
+
"""Interactively capture a session.
|
|
230
|
+
|
|
231
|
+
Launches a HEADED browser at ``url``, lets a human log in, then - after
|
|
232
|
+
``wait_for_signal()`` returns - persists the auth. Two modes:
|
|
233
|
+
|
|
234
|
+
* default: capture the context's storageState to ``sessions/<name>.json``.
|
|
235
|
+
* ``persistent=True``: drive a persistent Chromium profile at
|
|
236
|
+
``sessions/<name>.profile`` — the login is already saved on disk in that
|
|
237
|
+
dir, so we just close. Use for IndexedDB-auth sites (WhatsApp Web).
|
|
238
|
+
|
|
239
|
+
``wait_for_signal`` defaults to blocking on a line from stdin (ENTER).
|
|
240
|
+
|
|
241
|
+
``wait_seconds`` selects a NON-STDIN wait instead: hold the browser open for
|
|
242
|
+
up to that long while the human logs in. Required when an agent launches the
|
|
243
|
+
flow — agent stdin is EOF, so the ENTER wait returns instantly and saves a
|
|
244
|
+
half-authenticated profile (see WEB-AUTOMATION-NOTES.md). With
|
|
245
|
+
``wait_until_url_excludes`` the wait ends early, as soon as the address bar
|
|
246
|
+
leaves the login host (e.g. ``accounts.google.com``), then settles briefly.
|
|
247
|
+
"""
|
|
248
|
+
sessions.validate_name(name)
|
|
249
|
+
if not url:
|
|
250
|
+
raise UsageError("save_session requires a --url to open for login")
|
|
251
|
+
if wait_seconds is not None and wait_seconds <= 0:
|
|
252
|
+
raise UsageError("--wait-seconds must be a positive number of seconds")
|
|
253
|
+
if wait_for_signal is None and wait_seconds is None:
|
|
254
|
+
wait_for_signal = _block_on_enter
|
|
255
|
+
|
|
256
|
+
if persistent:
|
|
257
|
+
profile = sessions.profile_dir(name)
|
|
258
|
+
profile.mkdir(parents=True, exist_ok=True)
|
|
259
|
+
driver = driver_factory(storage_state=None, headless=False,
|
|
260
|
+
channel=channel, user_data_dir=str(profile))
|
|
261
|
+
driver.start()
|
|
262
|
+
cookies_saved = 0
|
|
263
|
+
try:
|
|
264
|
+
driver.goto(url)
|
|
265
|
+
# human logs in; the profile auto-persists to disk
|
|
266
|
+
waited = _run_wait(driver, wait_for_signal, wait_seconds,
|
|
267
|
+
wait_until_url_excludes)
|
|
268
|
+
# Snapshot live cookies (incl. session-scoped ones) BEFORE close.
|
|
269
|
+
# The profile persists localStorage/IndexedDB but NOT session
|
|
270
|
+
# cookies, so this sidecar is the only durable copy for cookie-auth
|
|
271
|
+
# sites. Re-injected by open_session on every subsequent run.
|
|
272
|
+
grab = getattr(driver, "get_cookies", None)
|
|
273
|
+
if callable(grab):
|
|
274
|
+
cookies = grab() or []
|
|
275
|
+
if cookies:
|
|
276
|
+
sessions.write_cookies(name, cookies)
|
|
277
|
+
cookies_saved = len(cookies)
|
|
278
|
+
finally:
|
|
279
|
+
_safe_close(driver)
|
|
280
|
+
out = {"session": name, "profile": str(profile), "url": url,
|
|
281
|
+
"persistent": True, "cookies_saved": cookies_saved}
|
|
282
|
+
out.update(waited)
|
|
283
|
+
return out
|
|
284
|
+
|
|
285
|
+
driver = driver_factory(storage_state=None, headless=False, channel=channel)
|
|
286
|
+
driver.start()
|
|
287
|
+
try:
|
|
288
|
+
driver.goto(url)
|
|
289
|
+
waited = _run_wait(driver, wait_for_signal, wait_seconds,
|
|
290
|
+
wait_until_url_excludes)
|
|
291
|
+
state = driver.storage_state()
|
|
292
|
+
finally:
|
|
293
|
+
_safe_close(driver)
|
|
294
|
+
path = sessions.write_state(name, state)
|
|
295
|
+
out = {"session": name, "path": str(path), "url": url}
|
|
296
|
+
out.update(waited)
|
|
297
|
+
return out
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
# --- internals ------------------------------------------------------------
|
|
301
|
+
|
|
302
|
+
_POLL_SECONDS = 2 # how often the login poller re-reads the address bar
|
|
303
|
+
_SETTLE_SECONDS = 8 # post-redirect settle so auth cookies land before snapshot
|
|
304
|
+
_HOLD_PROBE_MS = 500 # per-poll selector probe during a human-handoff hold
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def _run_wait(driver, wait_for_signal, wait_seconds, url_excludes) -> dict:
|
|
308
|
+
"""Hold the browser open while the human logs in.
|
|
309
|
+
|
|
310
|
+
Returns a small report merged into the action output so the caller can tell
|
|
311
|
+
a completed login from a timeout — never trust ``cookies_saved`` for that.
|
|
312
|
+
"""
|
|
313
|
+
if wait_seconds is None:
|
|
314
|
+
wait_for_signal()
|
|
315
|
+
return {"waited_for": "enter"}
|
|
316
|
+
|
|
317
|
+
import sys
|
|
318
|
+
import time
|
|
319
|
+
|
|
320
|
+
print(f"\n>>> Browser open. Log in - saving automatically once you are "
|
|
321
|
+
f"through (up to {wait_seconds}s).", file=sys.stderr, flush=True)
|
|
322
|
+
|
|
323
|
+
deadline = time.monotonic() + wait_seconds
|
|
324
|
+
detected = False
|
|
325
|
+
while time.monotonic() < deadline:
|
|
326
|
+
time.sleep(_POLL_SECONDS)
|
|
327
|
+
if not url_excludes:
|
|
328
|
+
continue
|
|
329
|
+
try:
|
|
330
|
+
current = driver.current_url() or ""
|
|
331
|
+
except Exception: # noqa: BLE001 - browser may be mid-navigation
|
|
332
|
+
continue
|
|
333
|
+
if url_excludes not in current:
|
|
334
|
+
detected = True
|
|
335
|
+
break
|
|
336
|
+
|
|
337
|
+
report = {"waited_for": "url" if url_excludes else "timer",
|
|
338
|
+
"login_detected": detected}
|
|
339
|
+
if detected:
|
|
340
|
+
# Let post-redirect cookies/localStorage settle before we snapshot.
|
|
341
|
+
print(">>> Login detected - settling before save...",
|
|
342
|
+
file=sys.stderr, flush=True)
|
|
343
|
+
time.sleep(_SETTLE_SECONDS)
|
|
344
|
+
try:
|
|
345
|
+
report["final_url"] = driver.current_url()
|
|
346
|
+
except Exception: # noqa: BLE001
|
|
347
|
+
pass
|
|
348
|
+
elif url_excludes:
|
|
349
|
+
print(">>> Timed out still on the login host — session NOT confirmed.",
|
|
350
|
+
file=sys.stderr, flush=True)
|
|
351
|
+
return report
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def _run_hold(driver, hold_seconds: int, until_selector: str | None,
|
|
355
|
+
until_url_excludes: str | None) -> dict:
|
|
356
|
+
"""Hold a headed browser open after the steps so a human can finish the job.
|
|
357
|
+
|
|
358
|
+
Distinct from ``_run_wait`` (which serves save-session's login capture and
|
|
359
|
+
reports ``login_detected``): this one also polls for a SELECTOR, and a
|
|
360
|
+
timeout here is a normal outcome rather than a suspect one - the human is
|
|
361
|
+
allowed to walk away. Returns
|
|
362
|
+
``{"held_seconds", "completed", "reason"}`` with reason
|
|
363
|
+
``selector`` | ``url`` | ``timeout``.
|
|
364
|
+
|
|
365
|
+
``completed`` is ADVISORY, not proof - same caveat as ``login_detected``.
|
|
366
|
+
The authoritative check stays ``final_url`` + ``diagnostics``.
|
|
367
|
+
"""
|
|
368
|
+
import sys
|
|
369
|
+
import time
|
|
370
|
+
|
|
371
|
+
print(f"\n>>> Steps done. Browser stays open up to {hold_seconds}s - review "
|
|
372
|
+
f"and complete the action yourself.", file=sys.stderr, flush=True)
|
|
373
|
+
|
|
374
|
+
started = time.monotonic()
|
|
375
|
+
deadline = started + hold_seconds
|
|
376
|
+
reason = "timeout"
|
|
377
|
+
while time.monotonic() < deadline:
|
|
378
|
+
time.sleep(_POLL_SECONDS)
|
|
379
|
+
if until_selector:
|
|
380
|
+
try:
|
|
381
|
+
driver.wait_for(until_selector, timeout=_HOLD_PROBE_MS)
|
|
382
|
+
reason = "selector"
|
|
383
|
+
break
|
|
384
|
+
except Exception: # noqa: BLE001 - not there yet is the normal case
|
|
385
|
+
pass
|
|
386
|
+
if until_url_excludes:
|
|
387
|
+
try:
|
|
388
|
+
current = driver.current_url() or ""
|
|
389
|
+
except Exception: # noqa: BLE001 - may be mid-navigation
|
|
390
|
+
continue
|
|
391
|
+
if until_url_excludes not in current:
|
|
392
|
+
reason = "url"
|
|
393
|
+
break
|
|
394
|
+
|
|
395
|
+
held = round(time.monotonic() - started, 1)
|
|
396
|
+
completed = reason != "timeout"
|
|
397
|
+
if completed:
|
|
398
|
+
print(f">>> Human action detected ({reason}) after {held}s.",
|
|
399
|
+
file=sys.stderr, flush=True)
|
|
400
|
+
else:
|
|
401
|
+
print(f">>> Hold expired after {held}s with no action detected - the "
|
|
402
|
+
f"steps still ran.", file=sys.stderr, flush=True)
|
|
403
|
+
return {"held_seconds": held, "completed": completed, "reason": reason}
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def _block_on_enter() -> None:
|
|
407
|
+
import sys
|
|
408
|
+
print(
|
|
409
|
+
"\n>>> Log in to the site in the opened browser window. "
|
|
410
|
+
"When you are fully logged in, return here and press ENTER to save "
|
|
411
|
+
"the session...",
|
|
412
|
+
file=sys.stderr, flush=True,
|
|
413
|
+
)
|
|
414
|
+
try:
|
|
415
|
+
sys.stdin.readline()
|
|
416
|
+
except (EOFError, KeyboardInterrupt):
|
|
417
|
+
pass
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def _diagnostics(driver) -> dict:
|
|
421
|
+
"""Collect runtime diagnostics (console/page errors, failed/4xx-5xx requests) if the
|
|
422
|
+
driver supports it. Defensive: a driver without diagnostics() (e.g. test FakeDriver)
|
|
423
|
+
yields an empty dict and never breaks the call."""
|
|
424
|
+
fn = getattr(driver, "diagnostics", None)
|
|
425
|
+
try:
|
|
426
|
+
return fn() if callable(fn) else {}
|
|
427
|
+
except Exception: # noqa: BLE001
|
|
428
|
+
return {}
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
def _safe_close(driver) -> None:
|
|
432
|
+
close = getattr(driver, "close", None)
|
|
433
|
+
if callable(close):
|
|
434
|
+
try:
|
|
435
|
+
close()
|
|
436
|
+
except Exception: # noqa: BLE001
|
|
437
|
+
pass
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def _safe_url(driver) -> str | None:
|
|
441
|
+
try:
|
|
442
|
+
return driver.current_url()
|
|
443
|
+
except Exception: # noqa: BLE001
|
|
444
|
+
return None
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""Routing of the web tool's generic browser actions (run / get-text /
|
|
2
|
+
screenshot) through the serializing broker that OWNS the target session.
|
|
3
|
+
|
|
4
|
+
Why: brokers exist so exactly one process drives a tool's web session at a
|
|
5
|
+
time (tools/_lib/webserialize). But `web run --session whatsapp ...` used to
|
|
6
|
+
open the profile DIRECTLY — an ad-hoc debugging command could race the
|
|
7
|
+
whatsapp broker's warm browser and invalidate the session. So when the target
|
|
8
|
+
session is broker-owned (registry: whatsapp/ryver/fgo/mirro), the web CLI
|
|
9
|
+
translates the action into a step list and submits it to that broker's
|
|
10
|
+
``web-steps`` op instead; the broker executes it serialized, on its warm
|
|
11
|
+
browser. Unowned sessions (e.g. 'google') keep the direct behavior.
|
|
12
|
+
|
|
13
|
+
Escape hatches: ``--direct``, the owning tool's ``<PREFIX>_DIRECT`` env, or
|
|
14
|
+
``--channel`` (not carried by the op — a channel run stays in-process).
|
|
15
|
+
Inside a broker's own worker the owning tool's ``<PREFIX>_SERVICE_WORKER``
|
|
16
|
+
env disables routing automatically, so a worker executing web steps can never
|
|
17
|
+
recurse into itself.
|
|
18
|
+
"""
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from tools._lib.webserialize import client as ws_client
|
|
22
|
+
from tools._lib.webserialize import registry as ws_registry
|
|
23
|
+
from tools._lib.webserialize.config import BrokerConfig
|
|
24
|
+
|
|
25
|
+
_TAG_KEYS = ("via", "service_queue_wait_ms", "service_fallback")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def eligible(parsed, *, driver_factory, allow_service: bool) -> BrokerConfig | None:
|
|
29
|
+
"""The owning broker config when this invocation should route, else None."""
|
|
30
|
+
if not allow_service or driver_factory is not None:
|
|
31
|
+
return None
|
|
32
|
+
if getattr(parsed, "direct", False):
|
|
33
|
+
return None
|
|
34
|
+
if getattr(parsed, "channel", None):
|
|
35
|
+
return None
|
|
36
|
+
session = getattr(parsed, "session", None)
|
|
37
|
+
if not session:
|
|
38
|
+
return None
|
|
39
|
+
cfg = ws_registry.owner_of_session(session)
|
|
40
|
+
if cfg is None or not ws_client.enabled(cfg):
|
|
41
|
+
return None
|
|
42
|
+
return cfg
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def route(cfg: BrokerConfig, action: str, parsed, *, dispatch_direct) -> dict:
|
|
46
|
+
steps, url, reshape = _translate(action, parsed)
|
|
47
|
+
result = ws_client.web_steps(
|
|
48
|
+
cfg, parsed.session, steps, url=url,
|
|
49
|
+
headless=not getattr(parsed, "headed", False),
|
|
50
|
+
dispatch_direct=dispatch_direct,
|
|
51
|
+
)
|
|
52
|
+
if not isinstance(result, dict) or result.get("via") == "direct-fallback":
|
|
53
|
+
return result # fallback already ran the real handler; final shape
|
|
54
|
+
return reshape(result)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _tags(src: dict, dst: dict) -> dict:
|
|
58
|
+
for k in _TAG_KEYS:
|
|
59
|
+
if k in src:
|
|
60
|
+
dst.setdefault(k, src[k])
|
|
61
|
+
return dst
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _translate(action: str, parsed):
|
|
65
|
+
"""(steps, url, reshape) for one of the three generic browser actions."""
|
|
66
|
+
if action == "run":
|
|
67
|
+
from tools.web.handlers.browse import _load_steps
|
|
68
|
+
return _load_steps(parsed), parsed.url, lambda r: r
|
|
69
|
+
|
|
70
|
+
if action == "get-text":
|
|
71
|
+
steps: list[dict] = []
|
|
72
|
+
if parsed.wait:
|
|
73
|
+
steps.append({"do": "wait_for", "selector": parsed.wait})
|
|
74
|
+
step: dict = {"do": "extract_text", "name": "text"}
|
|
75
|
+
if parsed.selector:
|
|
76
|
+
step["selector"] = parsed.selector
|
|
77
|
+
steps.append(step)
|
|
78
|
+
|
|
79
|
+
def reshape(r: dict) -> dict:
|
|
80
|
+
return _tags(r, {
|
|
81
|
+
"session": parsed.session, "url": parsed.url,
|
|
82
|
+
"selector": parsed.selector,
|
|
83
|
+
"text": (r.get("results") or {}).get("text", ""),
|
|
84
|
+
"final_url": r.get("final_url"),
|
|
85
|
+
"diagnostics": r.get("diagnostics", {}),
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
return steps, parsed.url, reshape
|
|
89
|
+
|
|
90
|
+
if action == "screenshot":
|
|
91
|
+
steps = []
|
|
92
|
+
if parsed.wait:
|
|
93
|
+
steps.append({"do": "wait_for", "selector": parsed.wait})
|
|
94
|
+
steps.append({"do": "screenshot", "path": parsed.out,
|
|
95
|
+
"full_page": not parsed.viewport_only})
|
|
96
|
+
|
|
97
|
+
def reshape(r: dict) -> dict:
|
|
98
|
+
return _tags(r, {
|
|
99
|
+
"session": parsed.session, "url": parsed.url,
|
|
100
|
+
"path": parsed.out,
|
|
101
|
+
"final_url": r.get("final_url"),
|
|
102
|
+
"diagnostics": r.get("diagnostics", {}),
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
return steps, parsed.url, reshape
|
|
106
|
+
|
|
107
|
+
raise ValueError(f"no broker translation for web action {action!r}")
|