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,44 @@
|
|
|
1
|
+
"""Check a test double against the BrowserDriver contract.
|
|
2
|
+
|
|
3
|
+
Several tools drive a browser through `tools/web/steps.run_steps`, and each
|
|
4
|
+
keeps its own `FakeDriver` test double. When the real driver gains a parameter -
|
|
5
|
+
`click(..., force=...)` was the one that bit - every double that does not accept
|
|
6
|
+
it starts raising TypeError, and the break surfaces in an unrelated tool's suite
|
|
7
|
+
hours later, looking like that tool's bug.
|
|
8
|
+
|
|
9
|
+
A double is deliberately allowed to implement only the subset of methods its own
|
|
10
|
+
tests exercise. What it may NOT do is implement a method with a signature the
|
|
11
|
+
step runner cannot call. That is the only thing checked here.
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import inspect
|
|
16
|
+
|
|
17
|
+
from tools.web.driver import BrowserDriver
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def signature_mismatches(double: type) -> list[str]:
|
|
21
|
+
"""Parameters BrowserDriver defines that `double` could not accept.
|
|
22
|
+
|
|
23
|
+
Returns one readable line per problem, empty when the double is callable
|
|
24
|
+
everywhere the real driver is. A double taking **kwargs is exempt: it can
|
|
25
|
+
absorb anything, at the cost of not asserting on it.
|
|
26
|
+
"""
|
|
27
|
+
problems: list[str] = []
|
|
28
|
+
for name, proto_fn in inspect.getmembers(BrowserDriver, inspect.isfunction):
|
|
29
|
+
if name.startswith("_"):
|
|
30
|
+
continue
|
|
31
|
+
fake_fn = getattr(double, name, None)
|
|
32
|
+
if fake_fn is None:
|
|
33
|
+
continue # implementing a subset is fine
|
|
34
|
+
fake_params = inspect.signature(fake_fn).parameters
|
|
35
|
+
if any(p.kind is inspect.Parameter.VAR_KEYWORD
|
|
36
|
+
for p in fake_params.values()):
|
|
37
|
+
continue
|
|
38
|
+
for pname in inspect.signature(proto_fn).parameters:
|
|
39
|
+
if pname == "self" or pname in fake_params:
|
|
40
|
+
continue
|
|
41
|
+
problems.append(
|
|
42
|
+
f"{double.__name__}.{name}() cannot accept {pname!r}, which "
|
|
43
|
+
f"BrowserDriver.{name}() defines")
|
|
44
|
+
return problems
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Map exceptions to the framework error envelope: (code, message, details, exit_code).
|
|
2
|
+
|
|
3
|
+
The web tool raises:
|
|
4
|
+
- UsageError bad/missing CLI args or a malformed step -> invalid_argument, exit 2
|
|
5
|
+
- SessionError a named session file is missing/corrupt -> session_not_found, exit 1
|
|
6
|
+
- BrowserError Playwright failed (nav timeout, missing -> browser_error, exit 1
|
|
7
|
+
browser binary, selector not found, etc.)
|
|
8
|
+
Anything else -> generic 'error', exit 1.
|
|
9
|
+
|
|
10
|
+
Playwright is imported lazily everywhere so this module (and the tests) load
|
|
11
|
+
even when the browser binaries are not installed yet.
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class UsageError(Exception):
|
|
19
|
+
"""Bad/invalid arguments or step schema. Maps to 'invalid_argument', exit 2."""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class SessionError(Exception):
|
|
23
|
+
"""A named session is missing or its storageState file is unreadable.
|
|
24
|
+
|
|
25
|
+
Maps to 'session_not_found', exit 1.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class BrowserError(Exception):
|
|
30
|
+
"""A Playwright operation failed (navigation, selector, missing binary, ...).
|
|
31
|
+
|
|
32
|
+
``details`` is surfaced under the error envelope's details when present.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(self, message: str, details: dict[str, Any] | None = None):
|
|
36
|
+
self.details = details or {}
|
|
37
|
+
super().__init__(message)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def classify(exc: Exception) -> tuple[str, str, dict, int]:
|
|
41
|
+
if isinstance(exc, UsageError):
|
|
42
|
+
return "invalid_argument", str(exc), {}, 2
|
|
43
|
+
if isinstance(exc, SessionError):
|
|
44
|
+
return "session_not_found", str(exc), {}, 1
|
|
45
|
+
if isinstance(exc, BrowserError):
|
|
46
|
+
return "browser_error", str(exc) or exc.__class__.__name__, exc.details, 1
|
|
47
|
+
# Playwright raises its own Error/TimeoutError types. Map them generically
|
|
48
|
+
# to browser_error by class-name sniffing so we never import playwright here.
|
|
49
|
+
cls = exc.__class__.__name__
|
|
50
|
+
if cls in {"Error", "TimeoutError"} and "playwright" in (
|
|
51
|
+
type(exc).__module__ or ""
|
|
52
|
+
):
|
|
53
|
+
return "browser_error", str(exc) or cls, {}, 1
|
|
54
|
+
return "error", str(exc) or cls, {}, 1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Action handlers for the web tool."""
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
"""archive-document - capture a published document as a reviewable evidence set.
|
|
2
|
+
|
|
3
|
+
WHY THIS EXISTS. A published document (a terms page, a subscription agreement,
|
|
4
|
+
a policy PDF) is evidence. Quoting it later is only safe if three things are
|
|
5
|
+
kept together: the bytes exactly as the publisher served them, a rendering a
|
|
6
|
+
human can open without a network, and a text form that can be searched and
|
|
7
|
+
quoted. Screenshots lose the text, a markdown conversion loses the clause
|
|
8
|
+
numbering and pagination that a reader relies on, and a bare URL loses
|
|
9
|
+
everything the moment the publisher edits the page.
|
|
10
|
+
|
|
11
|
+
So every capture writes THREE artefacts into one folder named for the document:
|
|
12
|
+
|
|
13
|
+
<name>.html / .pdf the ORIGINAL response body, byte for byte. Never
|
|
14
|
+
rewritten. The sha256 in the manifest is this
|
|
15
|
+
file's hash, so a later capture of the same URL
|
|
16
|
+
can be compared against it to prove whether the
|
|
17
|
+
publisher changed the document.
|
|
18
|
+
<name>.self-contained.html (HTML only) the same markup with every stylesheet
|
|
19
|
+
fetched and inlined, so the document opens with
|
|
20
|
+
its layout intact on a machine with no network
|
|
21
|
+
and no repository access. The markup is otherwise
|
|
22
|
+
untouched.
|
|
23
|
+
<name>.md a text extraction for searching and quoting,
|
|
24
|
+
carrying a provenance header: title, the date the
|
|
25
|
+
document states about itself, source URL, fetch
|
|
26
|
+
timestamp, and the sha256 of the original.
|
|
27
|
+
|
|
28
|
+
PROVENANCE IS NOT OPTIONAL. Both readable artefacts carry the same header
|
|
29
|
+
block, because an extraction that travels without its source URL and fetch date
|
|
30
|
+
becomes an unattributable quote the first time someone copies it into a brief.
|
|
31
|
+
|
|
32
|
+
DATES. ``document_date_candidates`` reports date-like strings the document
|
|
33
|
+
states about ITSELF (near "last updated", "effective", "version", "revised").
|
|
34
|
+
They are CANDIDATES, reported in the order found and never reconciled: a page
|
|
35
|
+
that says two different things about its own date is a finding about the page,
|
|
36
|
+
not a defect to be quietly resolved here.
|
|
37
|
+
|
|
38
|
+
LOGIN-GATED PAGES ARE OUT OF SCOPE by design. This action performs an
|
|
39
|
+
unauthenticated fetch. A document behind a login is a fact worth recording as
|
|
40
|
+
unreachable, not one to be silently substituted with a summary; capture those
|
|
41
|
+
through ``web run`` / ``web get-text`` with a saved session instead.
|
|
42
|
+
"""
|
|
43
|
+
from __future__ import annotations
|
|
44
|
+
|
|
45
|
+
import argparse
|
|
46
|
+
import hashlib
|
|
47
|
+
import re
|
|
48
|
+
from datetime import datetime, timezone
|
|
49
|
+
from pathlib import Path
|
|
50
|
+
from urllib.parse import urljoin, urlparse
|
|
51
|
+
|
|
52
|
+
from tools.web.actiondef import ActionDef
|
|
53
|
+
from tools.web.errors import UsageError
|
|
54
|
+
|
|
55
|
+
# A publisher's edge (Cloudflare and friends) may serve a challenge page to a
|
|
56
|
+
# default urllib/requests agent. A real browser agent gets the document itself.
|
|
57
|
+
_UA = ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
|
|
58
|
+
"(KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36")
|
|
59
|
+
|
|
60
|
+
_HEADERS = {
|
|
61
|
+
"User-Agent": _UA,
|
|
62
|
+
"Accept": "text/html,application/xhtml+xml,application/pdf,*/*;q=0.8",
|
|
63
|
+
"Accept-Language": "en-GB,en;q=0.9",
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# Date-ish strings a document uses to state its own version. Deliberately broad:
|
|
67
|
+
# over-reporting a candidate is cheap, missing the one date counsel needs is not.
|
|
68
|
+
_DATE_PATTERNS = [
|
|
69
|
+
r"\b\d{1,2}[./-]\d{1,2}[./-]\d{4}\b",
|
|
70
|
+
r"\b\d{4}-\d{2}-\d{2}\b",
|
|
71
|
+
r"\b\d{1,2}\s+(?:January|February|March|April|May|June|July|August|September|October|November|December)\s+\d{4}\b",
|
|
72
|
+
r"\b(?:January|February|March|April|May|June|July|August|September|October|November|December)\s+\d{1,2},?\s+\d{4}\b",
|
|
73
|
+
]
|
|
74
|
+
_DATE_CONTEXT = re.compile(
|
|
75
|
+
r"(last\s+updated|last\s+revised|effective|version|revised|updated|"
|
|
76
|
+
r"in\s+effect|as\s+of|dated|valabil|actualizat)", re.I)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _sha256(data: bytes) -> str:
|
|
80
|
+
return hashlib.sha256(data).hexdigest()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _fetch(url: str, timeout: int) -> tuple[bytes, int, str, str]:
|
|
84
|
+
"""GET url with a browser agent. Returns (body, status, content_type, final_url)."""
|
|
85
|
+
import requests
|
|
86
|
+
try:
|
|
87
|
+
resp = requests.get(url, headers=_HEADERS, timeout=timeout,
|
|
88
|
+
allow_redirects=True)
|
|
89
|
+
except Exception as exc: # noqa: BLE001 - network shape varies by failure
|
|
90
|
+
raise UsageError(f"fetch failed for {url!r}: {exc}")
|
|
91
|
+
return (resp.content, resp.status_code,
|
|
92
|
+
resp.headers.get("Content-Type", ""), resp.url)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _is_pdf(body: bytes, content_type: str, url: str) -> bool:
|
|
96
|
+
return (body[:5] == b"%PDF-"
|
|
97
|
+
or "application/pdf" in content_type.lower()
|
|
98
|
+
or urlparse(url).path.lower().endswith(".pdf"))
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _soup(html: bytes):
|
|
102
|
+
from bs4 import BeautifulSoup
|
|
103
|
+
return BeautifulSoup(html, "lxml")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _extract_title(soup, fallback: str) -> str:
|
|
107
|
+
for getter in (lambda: soup.title.get_text(strip=True) if soup.title else None,
|
|
108
|
+
lambda: soup.h1.get_text(strip=True) if soup.h1 else None):
|
|
109
|
+
try:
|
|
110
|
+
value = getter()
|
|
111
|
+
except Exception: # noqa: BLE001 - malformed markup must not abort a capture
|
|
112
|
+
value = None
|
|
113
|
+
if value:
|
|
114
|
+
return value
|
|
115
|
+
return fallback
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _html_to_text(soup) -> str:
|
|
119
|
+
"""Visible text with block structure preserved.
|
|
120
|
+
|
|
121
|
+
Only script/style/noscript/template are dropped - they carry no text a
|
|
122
|
+
reader would quote. Nothing else is filtered: a navigation or footer line
|
|
123
|
+
in the extraction is noise, but silently dropping a region risks dropping
|
|
124
|
+
a clause that happens to sit in one.
|
|
125
|
+
"""
|
|
126
|
+
from bs4 import BeautifulSoup # noqa: F401 (soup already built by caller)
|
|
127
|
+
clone = _soup(str(soup).encode("utf-8"))
|
|
128
|
+
for tag in clone(["script", "style", "noscript", "template"]):
|
|
129
|
+
tag.decompose()
|
|
130
|
+
text = clone.get_text("\n")
|
|
131
|
+
lines = [ln.strip() for ln in text.splitlines()]
|
|
132
|
+
out: list[str] = []
|
|
133
|
+
for line in lines:
|
|
134
|
+
if line:
|
|
135
|
+
out.append(line)
|
|
136
|
+
elif out and out[-1] != "":
|
|
137
|
+
out.append("")
|
|
138
|
+
return "\n".join(out).strip()
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _pdf_to_text(path: Path) -> str:
|
|
142
|
+
try:
|
|
143
|
+
import fitz
|
|
144
|
+
with fitz.open(path) as doc:
|
|
145
|
+
return "\n\n".join(
|
|
146
|
+
f"--- page {i + 1} ---\n{page.get_text()}"
|
|
147
|
+
for i, page in enumerate(doc)
|
|
148
|
+
).strip()
|
|
149
|
+
except Exception: # noqa: BLE001 - fall through to the second engine
|
|
150
|
+
pass
|
|
151
|
+
try:
|
|
152
|
+
from pypdf import PdfReader
|
|
153
|
+
reader = PdfReader(str(path))
|
|
154
|
+
return "\n\n".join(
|
|
155
|
+
f"--- page {i + 1} ---\n{(pg.extract_text() or '')}"
|
|
156
|
+
for i, pg in enumerate(reader.pages)
|
|
157
|
+
).strip()
|
|
158
|
+
except Exception as exc: # noqa: BLE001
|
|
159
|
+
return f"[extraction failed: {exc}]"
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _date_candidates(text: str, limit: int = 12) -> list[dict]:
|
|
163
|
+
"""Date strings the document states about itself, with their context line.
|
|
164
|
+
|
|
165
|
+
Reported in document order and NEVER de-conflicted. Two different dates on
|
|
166
|
+
one document is a finding, not an error to resolve.
|
|
167
|
+
"""
|
|
168
|
+
found: list[dict] = []
|
|
169
|
+
seen: set[tuple[str, str]] = set()
|
|
170
|
+
for line in text.splitlines():
|
|
171
|
+
if not _DATE_CONTEXT.search(line):
|
|
172
|
+
continue
|
|
173
|
+
for pattern in _DATE_PATTERNS:
|
|
174
|
+
for match in re.findall(pattern, line):
|
|
175
|
+
key = (match, line[:80])
|
|
176
|
+
if key in seen:
|
|
177
|
+
continue
|
|
178
|
+
seen.add(key)
|
|
179
|
+
found.append({"date": match, "context": line.strip()[:200]})
|
|
180
|
+
if len(found) >= limit:
|
|
181
|
+
return found
|
|
182
|
+
return found
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _inline_stylesheets(soup, base_url: str, timeout: int) -> int:
|
|
186
|
+
"""Fetch every <link rel=stylesheet> and inline it as <style>.
|
|
187
|
+
|
|
188
|
+
Makes the capture open with its layout on a machine with no network. The
|
|
189
|
+
markup is not otherwise touched: only the link element is swapped for the
|
|
190
|
+
stylesheet it pointed at, and a comment records where each came from so the
|
|
191
|
+
substitution stays auditable.
|
|
192
|
+
"""
|
|
193
|
+
import requests
|
|
194
|
+
inlined = 0
|
|
195
|
+
for link in list(soup.find_all("link")):
|
|
196
|
+
rel = " ".join(link.get("rel") or []).lower()
|
|
197
|
+
href = link.get("href")
|
|
198
|
+
if "stylesheet" not in rel or not href:
|
|
199
|
+
continue
|
|
200
|
+
css_url = urljoin(base_url, href)
|
|
201
|
+
try:
|
|
202
|
+
resp = requests.get(css_url, headers=_HEADERS, timeout=timeout)
|
|
203
|
+
if resp.status_code != 200:
|
|
204
|
+
continue
|
|
205
|
+
css = resp.text
|
|
206
|
+
except Exception: # noqa: BLE001 - a missing stylesheet degrades, never aborts
|
|
207
|
+
continue
|
|
208
|
+
# url(...) inside the CSS is relative to the STYLESHEET, not the page,
|
|
209
|
+
# so rewrite to absolute or the inlined copy loses its fonts and images.
|
|
210
|
+
css = re.sub(
|
|
211
|
+
r"url\(\s*(['\"]?)(?!data:|https?:|//)([^)'\"]+)\1\s*\)",
|
|
212
|
+
lambda m: f"url({m.group(1)}{urljoin(css_url, m.group(2))}{m.group(1)})",
|
|
213
|
+
css)
|
|
214
|
+
style = soup.new_tag("style")
|
|
215
|
+
style.string = f"/* inlined from {css_url} */\n{css}"
|
|
216
|
+
link.replace_with(style)
|
|
217
|
+
inlined += 1
|
|
218
|
+
return inlined
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _header(fmt: str, meta: dict) -> str:
|
|
222
|
+
"""Provenance block prepended to every readable artefact."""
|
|
223
|
+
dates = meta["document_date_candidates"]
|
|
224
|
+
date_line = ("; ".join(f"{d['date']} ({d['context'][:60]})" for d in dates)
|
|
225
|
+
if dates else "NONE STATED ON THE DOCUMENT")
|
|
226
|
+
rows = [
|
|
227
|
+
("Document title (as published)", meta["title"]),
|
|
228
|
+
("Date stated on the document", date_line),
|
|
229
|
+
("Source URL", meta["url"]),
|
|
230
|
+
("Final URL after redirects", meta["final_url"]),
|
|
231
|
+
("HTTP status", str(meta["status"])),
|
|
232
|
+
("Fetched at (UTC)", meta["fetched_at"]),
|
|
233
|
+
("Original file", meta["original_name"]),
|
|
234
|
+
("SHA-256 of original", meta["sha256_original"]),
|
|
235
|
+
("Original size (bytes)", str(meta["bytes"])),
|
|
236
|
+
("Captured by", "web archive-document (Agents-and-Tools)"),
|
|
237
|
+
]
|
|
238
|
+
if fmt == "md":
|
|
239
|
+
body = "\n".join(f"| {k} | {v} |" for k, v in rows)
|
|
240
|
+
return (
|
|
241
|
+
f"# {meta['title']}\n\n"
|
|
242
|
+
"> **Working copy for review. The original is the authority.**\n"
|
|
243
|
+
"> This extraction is the document's text only; clause numbering, "
|
|
244
|
+
"layout and pagination live in the original file beside it.\n\n"
|
|
245
|
+
"| Field | Value |\n|---|---|\n" + body + "\n\n---\n\n"
|
|
246
|
+
)
|
|
247
|
+
return ""
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def archive_document(args) -> dict:
|
|
251
|
+
if bool(args.url) == bool(args.file):
|
|
252
|
+
raise UsageError("provide exactly one of --url or --file")
|
|
253
|
+
|
|
254
|
+
out_dir = Path(args.out_dir).expanduser()
|
|
255
|
+
name = args.name.strip()
|
|
256
|
+
if not name or "/" in name or "\\" in name:
|
|
257
|
+
raise UsageError("--name must be a single folder-safe token")
|
|
258
|
+
folder = out_dir / name
|
|
259
|
+
folder.mkdir(parents=True, exist_ok=True)
|
|
260
|
+
|
|
261
|
+
fetched_at = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
262
|
+
|
|
263
|
+
if args.url:
|
|
264
|
+
body, status, content_type, final_url = _fetch(args.url, args.timeout)
|
|
265
|
+
source = args.url
|
|
266
|
+
else:
|
|
267
|
+
src = Path(args.file).expanduser()
|
|
268
|
+
if not src.is_file():
|
|
269
|
+
raise UsageError(f"--file not found: {src}")
|
|
270
|
+
body = src.read_bytes()
|
|
271
|
+
status, content_type, final_url = 200, "", src.as_uri()
|
|
272
|
+
source = args.source_url or src.as_uri()
|
|
273
|
+
|
|
274
|
+
is_pdf = _is_pdf(body, content_type, final_url)
|
|
275
|
+
ext = "pdf" if is_pdf else "html"
|
|
276
|
+
original = folder / f"{name}.{ext}"
|
|
277
|
+
original.write_bytes(body) # byte for byte, never rewritten
|
|
278
|
+
|
|
279
|
+
meta = {
|
|
280
|
+
"title": args.title or name,
|
|
281
|
+
"url": source,
|
|
282
|
+
"final_url": final_url,
|
|
283
|
+
"status": status,
|
|
284
|
+
"fetched_at": fetched_at,
|
|
285
|
+
"original_name": original.name,
|
|
286
|
+
"sha256_original": _sha256(body),
|
|
287
|
+
"bytes": len(body),
|
|
288
|
+
"document_date_candidates": [],
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
self_contained: Path | None = None
|
|
292
|
+
inlined = 0
|
|
293
|
+
if is_pdf:
|
|
294
|
+
text = _pdf_to_text(original)
|
|
295
|
+
else:
|
|
296
|
+
soup = _soup(body)
|
|
297
|
+
meta["title"] = args.title or _extract_title(soup, name)
|
|
298
|
+
text = _html_to_text(soup)
|
|
299
|
+
if not args.no_self_contained:
|
|
300
|
+
sc_soup = _soup(body)
|
|
301
|
+
inlined = _inline_stylesheets(sc_soup, final_url, args.timeout)
|
|
302
|
+
if sc_soup.head:
|
|
303
|
+
base = sc_soup.new_tag("base", href=final_url)
|
|
304
|
+
sc_soup.head.insert(0, base)
|
|
305
|
+
self_contained = folder / f"{name}.self-contained.html"
|
|
306
|
+
self_contained.write_text(str(sc_soup), encoding="utf-8")
|
|
307
|
+
|
|
308
|
+
meta["document_date_candidates"] = _date_candidates(text)
|
|
309
|
+
|
|
310
|
+
extraction = folder / f"{name}.md"
|
|
311
|
+
extraction.write_text(_header("md", meta) + text, encoding="utf-8")
|
|
312
|
+
|
|
313
|
+
files = {"original": str(original), "extraction": str(extraction)}
|
|
314
|
+
hashes = {
|
|
315
|
+
"original": meta["sha256_original"],
|
|
316
|
+
"extraction": _sha256(extraction.read_bytes()),
|
|
317
|
+
}
|
|
318
|
+
if self_contained is not None:
|
|
319
|
+
files["self_contained"] = str(self_contained)
|
|
320
|
+
hashes["self_contained"] = _sha256(self_contained.read_bytes())
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
"name": name,
|
|
324
|
+
"dir": str(folder),
|
|
325
|
+
"url": source,
|
|
326
|
+
"final_url": final_url,
|
|
327
|
+
"status": status,
|
|
328
|
+
"content_type": content_type,
|
|
329
|
+
"kind": "pdf" if is_pdf else "html",
|
|
330
|
+
"title": meta["title"],
|
|
331
|
+
"fetched_at": fetched_at,
|
|
332
|
+
"bytes": len(body),
|
|
333
|
+
"stylesheets_inlined": inlined,
|
|
334
|
+
"chars_extracted": len(text),
|
|
335
|
+
"document_date_candidates": meta["document_date_candidates"],
|
|
336
|
+
"files": files,
|
|
337
|
+
"sha256": hashes,
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def _archive_args(p: argparse.ArgumentParser) -> None:
|
|
342
|
+
p.add_argument("--url", default=None,
|
|
343
|
+
help="URL of the document to capture (exactly one of --url/--file)")
|
|
344
|
+
p.add_argument("--file", default=None,
|
|
345
|
+
help="Local file to archive instead of fetching (already-downloaded original)")
|
|
346
|
+
p.add_argument("--source-url", default=None,
|
|
347
|
+
help="With --file: the URL the file came from, recorded in the header")
|
|
348
|
+
p.add_argument("--out-dir", required=True,
|
|
349
|
+
help="Base directory; a subfolder named --name is created inside it")
|
|
350
|
+
p.add_argument("--name", required=True,
|
|
351
|
+
help="Folder and file basename for the document (a slug, not a URL)")
|
|
352
|
+
p.add_argument("--title", default=None,
|
|
353
|
+
help="Published title override; default reads <title>/<h1>")
|
|
354
|
+
p.add_argument("--timeout", type=int, default=60,
|
|
355
|
+
help="Per-request timeout in seconds (default 60)")
|
|
356
|
+
p.add_argument("--no-self-contained", action="store_true",
|
|
357
|
+
help="Skip the stylesheet-inlined copy (original + extraction only)")
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
ACTIONS = {
|
|
361
|
+
"archive-document": ActionDef(
|
|
362
|
+
archive_document, _archive_args, needs_driver=False,
|
|
363
|
+
description=("Capture a published document as original bytes + a "
|
|
364
|
+
"self-contained rendering + a text extraction, each with "
|
|
365
|
+
"a provenance header and sha256."),
|
|
366
|
+
),
|
|
367
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""Browser-action handlers: run, get-text, screenshot.
|
|
2
|
+
|
|
3
|
+
Each receives a ``driver_factory`` (injected by the dispatcher) as its first
|
|
4
|
+
argument, then the parsed args. The factory builds a BrowserDriver from kwargs
|
|
5
|
+
(``storage_state=``, ``headless=``, ``channel=``); in production it is
|
|
6
|
+
``PlaywrightDriver``, in tests it is a FakeDriver constructor. The handlers call
|
|
7
|
+
into ``tools.web.api`` passing the factory through, so the whole flow is
|
|
8
|
+
exercised without a real browser.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import json
|
|
14
|
+
|
|
15
|
+
from tools.web import api
|
|
16
|
+
from tools.web.actiondef import ActionDef
|
|
17
|
+
from tools.web.errors import UsageError
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _load_steps(args) -> list:
|
|
21
|
+
"""Resolve the step list from --actions (inline JSON) or --actions-file."""
|
|
22
|
+
if args.actions and args.actions_file:
|
|
23
|
+
raise UsageError("provide either --actions or --actions-file, not both")
|
|
24
|
+
raw = None
|
|
25
|
+
if args.actions:
|
|
26
|
+
raw = args.actions
|
|
27
|
+
elif args.actions_file:
|
|
28
|
+
try:
|
|
29
|
+
with open(args.actions_file, encoding="utf-8") as fh:
|
|
30
|
+
raw = fh.read()
|
|
31
|
+
except OSError as exc:
|
|
32
|
+
raise UsageError(f"cannot read --actions-file {args.actions_file!r}: {exc}")
|
|
33
|
+
else:
|
|
34
|
+
raise UsageError("provide --actions (JSON array) or --actions-file")
|
|
35
|
+
try:
|
|
36
|
+
steps = json.loads(raw)
|
|
37
|
+
except ValueError as exc:
|
|
38
|
+
raise UsageError(f"--actions is not valid JSON: {exc}")
|
|
39
|
+
if not isinstance(steps, list):
|
|
40
|
+
raise UsageError("--actions must be a JSON array of step objects")
|
|
41
|
+
return steps
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def run(driver_factory, args) -> dict:
|
|
45
|
+
steps = _load_steps(args)
|
|
46
|
+
return api.run_steps(
|
|
47
|
+
args.session, steps, url=args.url,
|
|
48
|
+
headless=not args.headed, channel=args.channel,
|
|
49
|
+
hold_seconds=args.hold_seconds,
|
|
50
|
+
hold_until_selector=args.hold_until_selector,
|
|
51
|
+
hold_until_url_excludes=args.hold_until_url_excludes,
|
|
52
|
+
driver_factory=driver_factory,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _run_args(p: argparse.ArgumentParser) -> None:
|
|
57
|
+
p.add_argument("--session", required=True, help="Saved session name to load")
|
|
58
|
+
p.add_argument("--url", default=None,
|
|
59
|
+
help="Optional URL to visit before running the steps")
|
|
60
|
+
p.add_argument("--actions", default=None,
|
|
61
|
+
help="Inline JSON array of steps (see README for the step schema)")
|
|
62
|
+
p.add_argument("--actions-file", default=None,
|
|
63
|
+
help="Path to a JSON file containing the steps array")
|
|
64
|
+
p.add_argument("--headed", action="store_true",
|
|
65
|
+
help="Show the browser window (default: headless)")
|
|
66
|
+
p.add_argument("--channel", default=None,
|
|
67
|
+
help="Chromium channel: 'chrome' or 'msedge'")
|
|
68
|
+
p.add_argument("--hold-seconds", type=int, default=None,
|
|
69
|
+
help="After the last step, keep the (headed) browser open up "
|
|
70
|
+
"to N seconds so a human can review and complete the "
|
|
71
|
+
"action themselves. Requires --headed. A hold that "
|
|
72
|
+
"expires is still a successful run")
|
|
73
|
+
p.add_argument("--hold-until-selector", default=None,
|
|
74
|
+
help="End the hold early once this selector appears (i.e. "
|
|
75
|
+
"the human acted). Requires --hold-seconds")
|
|
76
|
+
p.add_argument("--hold-until-url-excludes", default=None,
|
|
77
|
+
help="End the hold early once the address bar leaves this "
|
|
78
|
+
"host. Requires --hold-seconds")
|
|
79
|
+
p.add_argument("--direct", action="store_true",
|
|
80
|
+
help="Bypass the owning tool's serializing broker and drive "
|
|
81
|
+
"the browser in-process (backup; only safe when that "
|
|
82
|
+
"broker is stopped / idle-closed)")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def get_text(driver_factory, args) -> dict:
|
|
86
|
+
return api.get_text(
|
|
87
|
+
args.session, args.url, selector=args.selector, wait=args.wait,
|
|
88
|
+
headless=not args.headed, channel=args.channel,
|
|
89
|
+
driver_factory=driver_factory,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _get_text_args(p: argparse.ArgumentParser) -> None:
|
|
94
|
+
p.add_argument("--session", required=True, help="Saved session name to load")
|
|
95
|
+
p.add_argument("--url", required=True, help="URL to navigate to")
|
|
96
|
+
p.add_argument("--selector", default=None,
|
|
97
|
+
help="Optional CSS selector; default reads the whole page body")
|
|
98
|
+
p.add_argument("--wait", default=None,
|
|
99
|
+
help="Optional selector to await before reading (for SPAs)")
|
|
100
|
+
p.add_argument("--headed", action="store_true", help="Show the browser window")
|
|
101
|
+
p.add_argument("--channel", default=None, help="Chromium channel: 'chrome'|'msedge'")
|
|
102
|
+
p.add_argument("--direct", action="store_true",
|
|
103
|
+
help="Bypass the owning tool's serializing broker and drive "
|
|
104
|
+
"the browser in-process (backup; only safe when that "
|
|
105
|
+
"broker is stopped / idle-closed)")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def screenshot(driver_factory, args) -> dict:
|
|
109
|
+
return api.screenshot(
|
|
110
|
+
args.session, args.url, args.out, full_page=not args.viewport_only,
|
|
111
|
+
wait=args.wait, headless=not args.headed, channel=args.channel,
|
|
112
|
+
driver_factory=driver_factory,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _screenshot_args(p: argparse.ArgumentParser) -> None:
|
|
117
|
+
p.add_argument("--session", required=True, help="Saved session name to load")
|
|
118
|
+
p.add_argument("--url", required=True, help="URL to capture")
|
|
119
|
+
p.add_argument("--out", required=True, help="Output image path (.png)")
|
|
120
|
+
p.add_argument("--viewport-only", action="store_true",
|
|
121
|
+
help="Capture only the viewport (default: full page)")
|
|
122
|
+
p.add_argument("--wait", default=None, help="Optional selector to await first")
|
|
123
|
+
p.add_argument("--headed", action="store_true", help="Show the browser window")
|
|
124
|
+
p.add_argument("--channel", default=None, help="Chromium channel: 'chrome'|'msedge'")
|
|
125
|
+
p.add_argument("--direct", action="store_true",
|
|
126
|
+
help="Bypass the owning tool's serializing broker and drive "
|
|
127
|
+
"the browser in-process (backup; only safe when that "
|
|
128
|
+
"broker is stopped / idle-closed)")
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def render_pdf(driver_factory, args) -> dict:
|
|
132
|
+
if bool(args.html) == bool(args.html_file):
|
|
133
|
+
raise UsageError("provide exactly one of --html or --html-file")
|
|
134
|
+
if args.html_file:
|
|
135
|
+
try:
|
|
136
|
+
with open(args.html_file, encoding="utf-8") as fh:
|
|
137
|
+
html = fh.read()
|
|
138
|
+
except OSError as exc:
|
|
139
|
+
raise UsageError(f"cannot read --html-file {args.html_file!r}: {exc}")
|
|
140
|
+
else:
|
|
141
|
+
html = args.html
|
|
142
|
+
if bool(args.width) != bool(args.height):
|
|
143
|
+
raise UsageError("--width and --height go together (a custom sheet needs both)")
|
|
144
|
+
return api.render_pdf(html, args.out, fmt=args.format,
|
|
145
|
+
width=args.width, height=args.height, margin=args.margin,
|
|
146
|
+
driver_factory=driver_factory)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _render_pdf_args(p: argparse.ArgumentParser) -> None:
|
|
150
|
+
p.add_argument("--html", default=None, help="Inline HTML string to render")
|
|
151
|
+
p.add_argument("--html-file", dest="html_file", default=None,
|
|
152
|
+
help="Path to an HTML file to render")
|
|
153
|
+
p.add_argument("--out", required=True, help="Output PDF path (.pdf)")
|
|
154
|
+
p.add_argument("--format", default="A4",
|
|
155
|
+
help="Paper size: A4 (default) / Letter / Legal ...")
|
|
156
|
+
p.add_argument("--width", default=None,
|
|
157
|
+
help="Custom page width as a CSS length (e.g. 1000mm); needs --height, overrides --format")
|
|
158
|
+
p.add_argument("--height", default=None,
|
|
159
|
+
help="Custom page height as a CSS length (e.g. 2000mm); needs --width")
|
|
160
|
+
p.add_argument("--margin", default=None,
|
|
161
|
+
help="One CSS length for all four margins (0 for full-bleed artwork); "
|
|
162
|
+
"default keeps the document margins 12/14/12/12 mm")
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
ACTIONS = {
|
|
166
|
+
"run": ActionDef(
|
|
167
|
+
run, _run_args,
|
|
168
|
+
description="Load a session and run a declarative step list; return collected JSON.",
|
|
169
|
+
),
|
|
170
|
+
"render-pdf": ActionDef(
|
|
171
|
+
render_pdf, _render_pdf_args,
|
|
172
|
+
description="Render an HTML string/file to a PDF (session-less, headless Chromium).",
|
|
173
|
+
),
|
|
174
|
+
"get-text": ActionDef(
|
|
175
|
+
get_text, _get_text_args,
|
|
176
|
+
description="Load a session, open a URL, return visible text (whole page or a selector).",
|
|
177
|
+
),
|
|
178
|
+
"screenshot": ActionDef(
|
|
179
|
+
screenshot, _screenshot_args,
|
|
180
|
+
description="Load a session, open a URL, save a screenshot.",
|
|
181
|
+
),
|
|
182
|
+
}
|