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,191 @@
|
|
|
1
|
+
"""Parse a PROCESIO flow (export or live DTO) into a `FlowGraph`.
|
|
2
|
+
|
|
3
|
+
Pure + offline + case-insensitive: exports are PascalCase (`Actions`, `Ports`,
|
|
4
|
+
`CustomData`), the live Web-API is camelCase (`actions`, `ports`, `customData`). Same
|
|
5
|
+
DTOs, different case — so every field access goes through `_g` (case-insensitive get).
|
|
6
|
+
Never mutates the input.
|
|
7
|
+
|
|
8
|
+
The model it produces is documented in tools/procesio/PROCESIO-RESOURCE-MODEL-NOTES.md §1.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from tools.procesio.flowmodel.model import (
|
|
16
|
+
Container, Edge, FlowGraph, Node, SubprocessCall, VarRef,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _g(obj: Any, *names: str, default=None):
|
|
21
|
+
"""Case-insensitive get: try each name, matched against lowercased keys."""
|
|
22
|
+
if not isinstance(obj, dict):
|
|
23
|
+
return default
|
|
24
|
+
low = {str(k).lower(): v for k, v in obj.items()}
|
|
25
|
+
for n in names:
|
|
26
|
+
if n.lower() in low:
|
|
27
|
+
return low[n.lower()]
|
|
28
|
+
return default
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _is_bundle(obj: dict) -> bool:
|
|
32
|
+
return _g(obj, "Flows") is not None and _g(obj, "Actions") is None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _walk_settings(custom_data: dict):
|
|
36
|
+
"""Yield every setting dict in an action's CustomData.configuration, recursing into
|
|
37
|
+
side-panel settings whose `value` is itself a list of settings."""
|
|
38
|
+
for tab in _g(custom_data, "configuration", default=[]) or []:
|
|
39
|
+
for s in _g(tab, "settings", default=[]) or []:
|
|
40
|
+
if isinstance(s, dict):
|
|
41
|
+
yield s
|
|
42
|
+
val = _g(s, "value")
|
|
43
|
+
if isinstance(val, list):
|
|
44
|
+
for sub in val:
|
|
45
|
+
if isinstance(sub, dict) and (_g(sub, "label") or _g(sub, "type")):
|
|
46
|
+
yield sub
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _template_name(action: dict) -> str | None:
|
|
50
|
+
return _g(action, "ActionTemplateName", "actionTemplateName") \
|
|
51
|
+
or _g(action, "ActionName", "actionName")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _read_flow(flow: dict) -> FlowGraph:
|
|
55
|
+
flow_id = _g(flow, "Id")
|
|
56
|
+
fg = FlowGraph(flow_id=flow_id, title=_g(flow, "Title", "Name"))
|
|
57
|
+
|
|
58
|
+
actions = _g(flow, "Actions", default=[]) or []
|
|
59
|
+
area_ids: dict[str, dict] = {} # area node id -> its CustomData
|
|
60
|
+
for a in actions:
|
|
61
|
+
cd = _g(a, "CustomData", default={}) or {}
|
|
62
|
+
aid = _g(a, "Id")
|
|
63
|
+
tmpl = _template_name(a)
|
|
64
|
+
shape = _g(cd, "type")
|
|
65
|
+
pos = _g(cd, "position", default={}) or {}
|
|
66
|
+
asz = _g(cd, "areaSize", default={}) or {}
|
|
67
|
+
node = Node(
|
|
68
|
+
id=aid, template=tmpl, shape=shape, icon=_g(cd, "icon"),
|
|
69
|
+
position={"x": _g(pos, "x", default=0), "y": _g(pos, "y", default=0)},
|
|
70
|
+
size={"w": _g(asz, "width", default=48), "h": _g(asz, "height", default=48)},
|
|
71
|
+
parent_id=_g(a, "ParentId"),
|
|
72
|
+
input_ports=_g(cd, "inputPorts"), output_ports=_g(cd, "outputPorts"),
|
|
73
|
+
disabled=bool(_g(a, "IsDisabled", default=False)),
|
|
74
|
+
)
|
|
75
|
+
fg.nodes.append(node)
|
|
76
|
+
if shape == "area":
|
|
77
|
+
area_ids[aid] = cd
|
|
78
|
+
if tmpl == "Start":
|
|
79
|
+
fg.start_id = aid
|
|
80
|
+
elif tmpl == "Stop":
|
|
81
|
+
fg.stop_ids.append(aid)
|
|
82
|
+
|
|
83
|
+
# edges (stored on the source action)
|
|
84
|
+
for p in _g(a, "Ports", default=[]) or []:
|
|
85
|
+
src = _g(p, "SourceId")
|
|
86
|
+
dst = _g(p, "DestinationId")
|
|
87
|
+
if src and dst:
|
|
88
|
+
pdata = _g(p, "Data", default={}) or {}
|
|
89
|
+
fg.edges.append(Edge(
|
|
90
|
+
source=src, dest=dst, type=int(_g(p, "Type", default=0) or 0),
|
|
91
|
+
is_default=(_g(pdata, "isDefault") == "default")))
|
|
92
|
+
|
|
93
|
+
# subprocess + credential references via the action's settings
|
|
94
|
+
if tmpl in ("Call Subprocess", "Trigger Subprocess"):
|
|
95
|
+
target = None
|
|
96
|
+
for s in _walk_settings(cd):
|
|
97
|
+
if _g(s, "type") == "flow-list":
|
|
98
|
+
target = _g(s, "value")
|
|
99
|
+
break
|
|
100
|
+
fg.subprocess_calls.append(SubprocessCall(
|
|
101
|
+
action_id=aid, target_flow_id=target,
|
|
102
|
+
kind="call" if tmpl == "Call Subprocess" else "trigger"))
|
|
103
|
+
for s in _walk_settings(cd):
|
|
104
|
+
if _g(s, "type") == "credentials":
|
|
105
|
+
gid = _g(s, "value")
|
|
106
|
+
if gid and gid not in fg.resources["credentials"]:
|
|
107
|
+
fg.resources["credentials"].append(gid)
|
|
108
|
+
|
|
109
|
+
# containers: For-Each areas with their parented children
|
|
110
|
+
children_by_parent: dict[str, list[str]] = {}
|
|
111
|
+
for n in fg.nodes:
|
|
112
|
+
if n.parent_id:
|
|
113
|
+
children_by_parent.setdefault(n.parent_id, []).append(n.id)
|
|
114
|
+
for aid, cd in area_ids.items():
|
|
115
|
+
is_foreach = (_g(cd, "name") == "For Each")
|
|
116
|
+
fg.containers.append(Container(
|
|
117
|
+
id=aid, kind="foreach" if is_foreach else "area",
|
|
118
|
+
children=sorted(children_by_parent.get(aid, [])),
|
|
119
|
+
size={"w": _g(_g(cd, "areaSize", default={}) or {}, "width", default=0),
|
|
120
|
+
"h": _g(_g(cd, "areaSize", default={}) or {}, "height", default=0)}))
|
|
121
|
+
|
|
122
|
+
# variables (the flow's contract)
|
|
123
|
+
for v in _g(flow, "Variables", default=[]) or []:
|
|
124
|
+
fg.variables.append(VarRef(
|
|
125
|
+
id=_g(v, "Id"), name=_g(v, "Name"), type=_g(v, "Type"),
|
|
126
|
+
data_type=_g(v, "DataType"),
|
|
127
|
+
is_list=bool(_g(v, "IsList", default=False)),
|
|
128
|
+
is_required=bool(_g(v, "IsRequired", default=False)),
|
|
129
|
+
is_error=bool(_g(v, "IsError", default=False))))
|
|
130
|
+
|
|
131
|
+
# webhooks embedded on the flow
|
|
132
|
+
for w in _g(flow, "Webhooks", default=[]) or []:
|
|
133
|
+
wid = _g(w, "WebhookId", "Id")
|
|
134
|
+
if wid:
|
|
135
|
+
fg.resources["webhooks"].append(wid)
|
|
136
|
+
|
|
137
|
+
# deterministic ordering
|
|
138
|
+
fg.nodes.sort(key=lambda n: n.id or "")
|
|
139
|
+
fg.edges.sort(key=lambda e: (e.source or "", e.dest or "", e.type))
|
|
140
|
+
fg.containers.sort(key=lambda c: c.id or "")
|
|
141
|
+
fg.subprocess_calls.sort(key=lambda s: s.action_id or "")
|
|
142
|
+
return fg
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _coerce(source) -> dict:
|
|
146
|
+
if isinstance(source, dict):
|
|
147
|
+
return source
|
|
148
|
+
if isinstance(source, str):
|
|
149
|
+
return json.loads(source)
|
|
150
|
+
raise TypeError(f"unsupported source type: {type(source).__name__}")
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def read_flow(source, flow_id: str | None = None) -> FlowGraph:
|
|
154
|
+
"""Read one flow into a FlowGraph. `source` may be a flow dict, a bundle dict, or a
|
|
155
|
+
JSON string of either. `flow_id` is required only to disambiguate a multi-flow bundle.
|
|
156
|
+
"""
|
|
157
|
+
obj = _coerce(source)
|
|
158
|
+
if _is_bundle(obj):
|
|
159
|
+
flows = _g(obj, "Flows", default=[]) or []
|
|
160
|
+
if not flows:
|
|
161
|
+
raise ValueError("bundle has no flows")
|
|
162
|
+
if flow_id:
|
|
163
|
+
match = next((f for f in flows if _g(f, "Id") == flow_id), None)
|
|
164
|
+
if match is None:
|
|
165
|
+
raise ValueError(f"flow_id {flow_id} not found in bundle")
|
|
166
|
+
return _read_flow(match)
|
|
167
|
+
if len(flows) > 1:
|
|
168
|
+
ids = [_g(f, "Id") for f in flows]
|
|
169
|
+
raise ValueError(f"bundle has {len(flows)} flows; pass flow_id (one of {ids[:8]}…)")
|
|
170
|
+
return _read_flow(flows[0])
|
|
171
|
+
return _read_flow(obj)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def read_bundle(source) -> dict:
|
|
175
|
+
"""Read every flow in a bundle plus the cross-process (process→process) edge list.
|
|
176
|
+
|
|
177
|
+
Returns {"flows": {flow_id: FlowGraph.to_dict()}, "process_edges": [...]}.
|
|
178
|
+
"""
|
|
179
|
+
obj = _coerce(source)
|
|
180
|
+
flows = _g(obj, "Flows", default=[]) or ([obj] if _g(obj, "Actions") is not None else [])
|
|
181
|
+
graphs: dict[str, FlowGraph] = {}
|
|
182
|
+
for f in flows:
|
|
183
|
+
fg = _read_flow(f)
|
|
184
|
+
graphs[fg.flow_id] = fg
|
|
185
|
+
process_edges = []
|
|
186
|
+
for fid, fg in graphs.items():
|
|
187
|
+
for sc in fg.subprocess_calls:
|
|
188
|
+
if sc.target_flow_id:
|
|
189
|
+
process_edges.append({"source": fid, "target": sc.target_flow_id, "kind": sc.kind})
|
|
190
|
+
process_edges.sort(key=lambda e: (e["source"] or "", e["target"] or "", e["kind"]))
|
|
191
|
+
return {"flows": {k: v.to_dict() for k, v in graphs.items()}, "process_edges": process_edges}
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
"""Parameterize PROCESIO SQL Server actions.
|
|
2
|
+
|
|
3
|
+
The SAFE way to pass flow-variable values into an `Execute Query` / `Execute Command` action is
|
|
4
|
+
NAMED SQL parameters (`@name`) bound via the action's `Parameters config tab` (a `map-parameters`
|
|
5
|
+
setting) — values then travel as typed, driver-escaped SQL parameters. The UNSAFE way (and the wrong
|
|
6
|
+
action config) is to string-interpolate the value into the SQL text as `N'<%N%>'`; that is
|
|
7
|
+
SQL-injection-prone, especially where the value is user text (a contact name, a message, OCR).
|
|
8
|
+
|
|
9
|
+
This module detects inline-`<%N%>` SQL nodes and converts them to the parameterized form. It also
|
|
10
|
+
migrates the deprecated `Execute Query V2` template (inline-only) to `Execute Query` (which carries the
|
|
11
|
+
`Parameters config tab`). Pure: it mutates a raw flow DTO dict in place; callers fetch/validate/put.
|
|
12
|
+
|
|
13
|
+
See tools/procesio/PROCESIO-SQL-ACTIONS-NOTES.md for the full DTO shape and property ids.
|
|
14
|
+
"""
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import copy
|
|
18
|
+
import re
|
|
19
|
+
|
|
20
|
+
# 'Execute Query' template property ids (verified live 2026-07-03 on Chat Flow/Resolve Contact).
|
|
21
|
+
EQ_TEMPLATE = "Execute Query"
|
|
22
|
+
EQ_TEMPLATE_ID = "76470756-6dbd-4ab2-a4bf-88b47ed381ba"
|
|
23
|
+
# The deprecated 'Execute Query V2' template. CRUCIAL: the designer renders the action TYPE from the
|
|
24
|
+
# templateId, and the build put many SQL nodes on this template while LABELLING them "Execute Query".
|
|
25
|
+
# The map-parameters binding does NOT exist on V2, so a node must be migrated to EQ_TEMPLATE_ID (which
|
|
26
|
+
# the migration does) or the @params are unbound at runtime. Key it on templateId, never the label.
|
|
27
|
+
PID_CRED = "f96ff811-572f-084a-8cac-a74a2c2e365f" # 'Select Database Server' (credentials)
|
|
28
|
+
PID_SIDEPANEL = "8add0f17-b2b1-4d5f-962b-c5d400a4e2d4" # 'Execute Query' (side-pannel container)
|
|
29
|
+
PID_QUERY = "11350a1d-4139-d942-adcb-a2c2c52e5e22" # 'Query' (code-editor, sql)
|
|
30
|
+
PID_BIND = "73416282-bcfe-4934-9e40-a39f2bb33d2d" # 'Parameters config tab' (map-parameters)
|
|
31
|
+
PID_TIMEOUT = "9ce93b2d-5226-4228-a64d-3693c8d3e0e3" # 'Time Out' (number)
|
|
32
|
+
PID_OUTPUT = "8aa02e91-1a1e-a44a-b09b-6965d67da04d" # 'Output' (any)
|
|
33
|
+
|
|
34
|
+
# 'Execute Command' is a SECOND family with its OWN property ids - notably its own
|
|
35
|
+
# 'Parameters config tab' (0acb249e...), NOT the Execute Query one. Writing the Query binding id onto a
|
|
36
|
+
# Command node leaves every @param unbound at runtime with nothing to show for it, so the bind id must
|
|
37
|
+
# always be looked up per family (verified live 2026-08-22 against GET /api/Actions?getFullAction=true).
|
|
38
|
+
EC_TEMPLATE = "Execute Command"
|
|
39
|
+
EC_TEMPLATE_ID = "a1625da6-c093-4695-a97c-3c3d9a9b0cae"
|
|
40
|
+
EC_PID_CRED = "5f75a4fd-d0f5-4ac1-8257-467e50e7292e" # 'Select Database Server' (credentials)
|
|
41
|
+
EC_PID_SIDEPANEL = "975f25dc-1044-4488-b635-10a2039f8d89"
|
|
42
|
+
EC_PID_COMMAND = "824575f6-7652-4bc2-8186-63b32c92cc22" # 'Command' (code-editor, sql)
|
|
43
|
+
EC_PID_BIND = "0acb249e-8b21-4bfd-946c-1e65e26baa68" # 'Parameters config tab' (map-parameters)
|
|
44
|
+
EC_PID_TIMEOUT = "2be309c6-9144-4b27-a722-fbc9c89735c2" # 'Time Out' (number, required, 60..1800)
|
|
45
|
+
EC_PID_OUTPUT = "e6ffaa2d-2c32-412d-a9d4-b1038ece9d38" # 'Output' (number, required)
|
|
46
|
+
|
|
47
|
+
# role -> property id, per CURRENT template. `timeout_default` fills a required Time Out that a
|
|
48
|
+
# migrated legacy node never had, so the migration cannot leave the designer with an empty required field.
|
|
49
|
+
_CURRENT = {
|
|
50
|
+
EQ_TEMPLATE: {"templateId": EQ_TEMPLATE_ID, "cred": PID_CRED, "sidepanel": PID_SIDEPANEL,
|
|
51
|
+
"sql": PID_QUERY, "bind": PID_BIND, "timeout": PID_TIMEOUT, "output": PID_OUTPUT,
|
|
52
|
+
"timeout_default": None, "output_type": "any",
|
|
53
|
+
"description": "Execute a custom SQL Query on the target database.",
|
|
54
|
+
"labels": {PID_CRED: "Select Database Server", PID_SIDEPANEL: "Execute Query",
|
|
55
|
+
PID_QUERY: "Query", PID_TIMEOUT: "Time Out", PID_OUTPUT: "Output"}},
|
|
56
|
+
EC_TEMPLATE: {"templateId": EC_TEMPLATE_ID, "cred": EC_PID_CRED, "sidepanel": EC_PID_SIDEPANEL,
|
|
57
|
+
"sql": EC_PID_COMMAND, "bind": EC_PID_BIND, "timeout": EC_PID_TIMEOUT,
|
|
58
|
+
"output": EC_PID_OUTPUT, "timeout_default": "300", "output_type": "number",
|
|
59
|
+
"description": "Execute a custom SQL Command on the target database.",
|
|
60
|
+
"labels": {EC_PID_CRED: "Select Database Server", EC_PID_SIDEPANEL: "Execute Command",
|
|
61
|
+
EC_PID_COMMAND: "Command", EC_PID_TIMEOUT: "Time Out",
|
|
62
|
+
EC_PID_OUTPUT: "Output"}},
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# The property roles a family remap has to move. Order is irrelevant; completeness is not — a role
|
|
66
|
+
# left behind keeps the OLD template's property id on the node, which the designer then ignores.
|
|
67
|
+
_ROLE_KEYS = ("cred", "sidepanel", "sql", "bind", "timeout", "output")
|
|
68
|
+
|
|
69
|
+
# DEPRECATED templateId -> (family, {role: that template's property id}). Every one of these is
|
|
70
|
+
# inline-only (no map-parameters), so a node on one MUST be migrated before it can bind @params.
|
|
71
|
+
# Key on templateId, never the label: nodes on a legacy template are routinely LABELLED with the
|
|
72
|
+
# current template's name (all four collectors in one live workspace were, 2026-08-22).
|
|
73
|
+
_LEGACY = {
|
|
74
|
+
"a9f851c2-e0ba-4fee-9a06-5445ba000001": (EQ_TEMPLATE, { # Execute Query V2
|
|
75
|
+
"cred": "a9f851c2-e0ba-4fee-9a06-5445bc000011",
|
|
76
|
+
"sidepanel": "a9f851c2-e0ba-4fee-9a06-5445bc000012",
|
|
77
|
+
"output": "a9f851c2-e0ba-4fee-9a06-5445bc000013",
|
|
78
|
+
"sql": "a9f851c2-e0ba-4fee-9a06-5445bc000014",
|
|
79
|
+
"timeout": "a9f851c2-e0ba-4fee-9a06-5445bc000015"}),
|
|
80
|
+
"574a2ab1-4d24-4d6c-9483-f61597a6d5ff": (EQ_TEMPLATE, { # Execute Query V1
|
|
81
|
+
"cred": "a9d217b3-6a3c-44c5-81ff-581c860fb560",
|
|
82
|
+
"sidepanel": "0b5bedd7-cd08-49f3-ba70-9d24aa7239ef",
|
|
83
|
+
"output": "459b4db8-25f1-4903-9be8-3239312e93e6",
|
|
84
|
+
"sql": "487bcfdb-67fd-49c0-bf02-0fb614dbb800"}),
|
|
85
|
+
"c2760ff2-cd9e-49b4-b751-c05c88e06dac": (EC_TEMPLATE, { # Execute Command V1
|
|
86
|
+
"cred": "6701cb8b-3bde-4c7e-a45d-c37eaeff5e3d",
|
|
87
|
+
"sidepanel": "fea72099-4718-473d-a091-7749aa38305b",
|
|
88
|
+
"sql": "53896b0d-73a6-412f-9e67-224ca1daae7c",
|
|
89
|
+
"timeout": "f3452b3a-2c10-40df-9d34-2d2779dc6ed6",
|
|
90
|
+
"output": "f3452b3a-2c10-40df-9d34-2d2779dc6ed7"}),
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def family_of(node: dict) -> tuple[str, dict | None]:
|
|
95
|
+
"""(current-family name, legacy role map or None) for a SQL node, keyed on templateId.
|
|
96
|
+
|
|
97
|
+
Falls back to the label only when the templateId is unknown - a node built against a template
|
|
98
|
+
this table has not seen yet still parameterizes, it just does not migrate.
|
|
99
|
+
"""
|
|
100
|
+
tid = str(node.get("templateId") or "")
|
|
101
|
+
if tid in _LEGACY:
|
|
102
|
+
return _LEGACY[tid]
|
|
103
|
+
for fam, spec in _CURRENT.items():
|
|
104
|
+
if tid == spec["templateId"]:
|
|
105
|
+
return fam, None
|
|
106
|
+
label = node.get("actionTemplateName") or ""
|
|
107
|
+
return (EC_TEMPLATE if EC_TEMPLATE in label else EQ_TEMPLATE), None
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def bind_pid(node: dict) -> str:
|
|
111
|
+
"""The 'Parameters config tab' property id for THIS node's family."""
|
|
112
|
+
return _CURRENT[family_of(node)[0]]["bind"]
|
|
113
|
+
|
|
114
|
+
_SQL_KW = re.compile(r"\b(EXEC|SELECT|UPDATE|INSERT|DELETE|MERGE|DECLARE)\b", re.I)
|
|
115
|
+
_PLACEHOLDER = re.compile(r"<%(\d+)%>")
|
|
116
|
+
_SQL_TEMPLATES = ("Execute Query", "Execute Command") # includes 'Execute Query V2'
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def is_sql_node(node: dict) -> bool:
|
|
120
|
+
t = node.get("actionTemplateName", "") or ""
|
|
121
|
+
return any(k in t for k in _SQL_TEMPLATES)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _query_param(node: dict):
|
|
125
|
+
"""the parameters[] entry whose value is the SQL text still holding inline <%N%>."""
|
|
126
|
+
for p in node.get("parameters") or []:
|
|
127
|
+
v = p.get("value")
|
|
128
|
+
if isinstance(v, str) and _PLACEHOLDER.search(v) and _SQL_KW.search(v):
|
|
129
|
+
return p
|
|
130
|
+
return None
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _query_setting(node: dict):
|
|
134
|
+
"""(container-setting, query-sub-setting) inside the side-pannel; the designer copy of the SQL."""
|
|
135
|
+
for c in (node.get("customData") or {}).get("configuration") or []:
|
|
136
|
+
for s in c.get("settings") or []:
|
|
137
|
+
if isinstance(s.get("value"), list):
|
|
138
|
+
for sub in s["value"]:
|
|
139
|
+
if isinstance(sub, dict) and str(sub.get("label", "")).lower() in ("query", "command"):
|
|
140
|
+
return s, sub
|
|
141
|
+
return None, None
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def is_inline(node: dict) -> bool:
|
|
145
|
+
"""True if this SQL node string-interpolates a value as N'<%N%>' (the injectable anti-pattern)."""
|
|
146
|
+
qp = _query_param(node)
|
|
147
|
+
if not qp:
|
|
148
|
+
return False
|
|
149
|
+
return bool(re.search(r"N?'<%\d+%>'", qp["value"]))
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def scan(flow: dict) -> list[dict]:
|
|
153
|
+
"""List every SQL action in a flow with its inline/parameterized status."""
|
|
154
|
+
out = []
|
|
155
|
+
for a in flow.get("actions") or []:
|
|
156
|
+
if is_sql_node(a):
|
|
157
|
+
out.append({"actionName": a.get("actionName"), "id": a.get("id"),
|
|
158
|
+
"template": a.get("actionTemplateName"), "inline": is_inline(a)})
|
|
159
|
+
return out
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def find_node(flow: dict, key: str):
|
|
163
|
+
for a in flow.get("actions") or []:
|
|
164
|
+
if a.get("id") == key or a.get("actionName") == key:
|
|
165
|
+
return a
|
|
166
|
+
return None
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _designate_source(ve: dict) -> str:
|
|
170
|
+
return ve["variableId"] + ("." + ve["attribute"]["attributeId"] if ve.get("attribute") else "")
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def parameterize_node(node: dict) -> tuple[bool, str]:
|
|
174
|
+
"""Convert one inline-<%N%> SQL node to the parameterized form, in place.
|
|
175
|
+
|
|
176
|
+
Rewrites each `N'<%K%>'` (and the un-quoted forms) to `@pK`, moves the placeholder->variable map
|
|
177
|
+
into a `Parameters config tab` (map-parameters) binding, and — for a deprecated `Execute Query V2`
|
|
178
|
+
node — swaps the template to `Execute Query`. Literals stay inline. Returns (changed, message).
|
|
179
|
+
"""
|
|
180
|
+
if not is_sql_node(node):
|
|
181
|
+
return False, "not a SQL Server action (Execute Query / Execute Command)"
|
|
182
|
+
qp = _query_param(node)
|
|
183
|
+
if not qp:
|
|
184
|
+
return False, "already parameterized or no inline <%N%> in the SQL"
|
|
185
|
+
sql = qp["value"]
|
|
186
|
+
varmap = {v["id"]: v for v in (qp.get("variable") or [])}
|
|
187
|
+
idxs = sorted(set(int(m) for m in _PLACEHOLDER.findall(sql)) & set(varmap))
|
|
188
|
+
if not idxs:
|
|
189
|
+
return False, "no bound <%N%> placeholders to parameterize"
|
|
190
|
+
|
|
191
|
+
new_sql = sql
|
|
192
|
+
runtime, designer = [], []
|
|
193
|
+
for k in idxs:
|
|
194
|
+
for form in ("N'<%%%d%%>'" % k, "'<%%%d%%>'" % k, "<%%%d%%>" % k):
|
|
195
|
+
new_sql = new_sql.replace(form, "@p%d" % k)
|
|
196
|
+
ve = varmap[k]
|
|
197
|
+
runtime.append({"id": k,
|
|
198
|
+
"source": {"value": "<%%%d%%>" % k, "variable": [copy.deepcopy(ve)]},
|
|
199
|
+
"destination": {"value": "p%d" % k, "variable": []}})
|
|
200
|
+
designer.append({"id": k, "destination": "p%d" % k, "source": _designate_source(ve)})
|
|
201
|
+
|
|
202
|
+
# Migrate a node on a DEPRECATED template to its family's current one first (role-based id remap):
|
|
203
|
+
# every legacy template is inline-only, so without this the @params have no property to bind to.
|
|
204
|
+
fam, legacy = family_of(node)
|
|
205
|
+
if legacy:
|
|
206
|
+
_migrate_to_current(node, qp, fam, legacy)
|
|
207
|
+
pid_bind = _CURRENT[fam]["bind"]
|
|
208
|
+
|
|
209
|
+
# -- runtime form (what the engine executes) --
|
|
210
|
+
qp["value"] = new_sql
|
|
211
|
+
qp.pop("variable", None)
|
|
212
|
+
params = node.setdefault("parameters", [])
|
|
213
|
+
bp = next((p for p in params if p.get("tabPropertyId") == pid_bind), None)
|
|
214
|
+
if bp:
|
|
215
|
+
bp["value"] = runtime
|
|
216
|
+
else:
|
|
217
|
+
params.append({"tabPropertyId": pid_bind, "value": runtime})
|
|
218
|
+
|
|
219
|
+
# -- designer copy (customData side-pannel) --
|
|
220
|
+
setting, qsub = _query_setting(node)
|
|
221
|
+
if qsub is not None:
|
|
222
|
+
qsub["value"] = new_sql
|
|
223
|
+
lst = setting["value"]
|
|
224
|
+
existing = next((s for s in lst if isinstance(s, dict) and s.get("id") == pid_bind), None)
|
|
225
|
+
if existing:
|
|
226
|
+
existing["value"] = designer
|
|
227
|
+
else:
|
|
228
|
+
lst.insert(1, {"id": pid_bind, "dataTypeId": None, "label": "Parameters config tab",
|
|
229
|
+
"type": "map-parameters", "value": designer})
|
|
230
|
+
return True, "parameterized %d value(s): %s" % (len(idxs), ", ".join("@p%d" % k for k in idxs))
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _roles_of(family: str) -> dict:
|
|
234
|
+
"""{role: property id} for a CURRENT template, in the shape _migrate_to_current consumes."""
|
|
235
|
+
spec = _CURRENT[family]
|
|
236
|
+
return {role: spec[role] for role in _ROLE_KEYS if spec.get(role)}
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _output_settings(node: dict, pid: str):
|
|
240
|
+
"""Every designer setting carrying the Output property, at either nesting level."""
|
|
241
|
+
for cfg in (node.get("customData") or {}).get("configuration") or []:
|
|
242
|
+
for setting in cfg.get("settings") or []:
|
|
243
|
+
if setting.get("id") == pid:
|
|
244
|
+
yield setting
|
|
245
|
+
if isinstance(setting.get("value"), list):
|
|
246
|
+
for sub in setting["value"]:
|
|
247
|
+
if isinstance(sub, dict) and sub.get("id") == pid:
|
|
248
|
+
yield sub
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def convert_family(node: dict, target: str) -> tuple[bool, str]:
|
|
252
|
+
"""Move a SQL node between the Execute Command and Execute Query families, in place.
|
|
253
|
+
|
|
254
|
+
`Execute Query` carries a RESULT SET back into a flow variable; `Execute Command` carries
|
|
255
|
+
rows-affected (its Output property is typed `number`). So a Command node pointed at a procedure
|
|
256
|
+
that ends in SELECT throws away everything the procedure returns and still reports success —
|
|
257
|
+
there is no error to see, the output variable is simply a count. Converting the family is the
|
|
258
|
+
only fix, and it is a role-based property-id remap in both the runtime `parameters[]` and the
|
|
259
|
+
designer `customData`, plus the Output setting's type and the labels a later reader will trust.
|
|
260
|
+
|
|
261
|
+
The SQL text, credential, timeout and `@param` binding are carried across untouched. A node on a
|
|
262
|
+
deprecated template is refused rather than half-converted: run `sql-parameterize` first, which
|
|
263
|
+
migrates it onto its family's current template. Returns (changed, message).
|
|
264
|
+
"""
|
|
265
|
+
if target not in _CURRENT:
|
|
266
|
+
raise ValueError("unknown SQL action family: %s (expected %r or %r)"
|
|
267
|
+
% (target, EQ_TEMPLATE, EC_TEMPLATE))
|
|
268
|
+
if not is_sql_node(node):
|
|
269
|
+
return False, "not a SQL Server action (Execute Query / Execute Command)"
|
|
270
|
+
|
|
271
|
+
source, legacy = family_of(node)
|
|
272
|
+
if legacy:
|
|
273
|
+
return False, ("node is on a deprecated template (%s) - run sql-parameterize first to "
|
|
274
|
+
"migrate it onto its family's current template" % node.get("templateId"))
|
|
275
|
+
if source == target:
|
|
276
|
+
return False, "already %s" % target
|
|
277
|
+
|
|
278
|
+
src_sql_pid = _CURRENT[source]["sql"]
|
|
279
|
+
sql_param = next((p for p in node.get("parameters") or []
|
|
280
|
+
if p.get("tabPropertyId") == src_sql_pid), None)
|
|
281
|
+
if sql_param is None:
|
|
282
|
+
return False, "no SQL parameter (%s) found on the node" % src_sql_pid
|
|
283
|
+
|
|
284
|
+
cur = _CURRENT[target]
|
|
285
|
+
_migrate_to_current(node, sql_param, target, _roles_of(source))
|
|
286
|
+
|
|
287
|
+
# customData carries three things the role remap does not reach, and each one is what the next
|
|
288
|
+
# reader (or the designer) uses to decide what this node IS.
|
|
289
|
+
custom = node.get("customData") or {}
|
|
290
|
+
if isinstance(custom.get("description"), str):
|
|
291
|
+
custom["description"] = cur["description"]
|
|
292
|
+
for cfg in custom.get("configuration") or []:
|
|
293
|
+
if cfg.get("label") == source:
|
|
294
|
+
cfg["label"] = target
|
|
295
|
+
for setting in _output_settings(node, cur["output"]):
|
|
296
|
+
setting["type"] = cur["output_type"]
|
|
297
|
+
|
|
298
|
+
return True, "converted %s -> %s" % (source, target)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def rebind_output(node: dict, variable_id: str) -> tuple[bool, str]:
|
|
302
|
+
"""Point a SQL node's Output at a different flow variable, in both layers, in place.
|
|
303
|
+
|
|
304
|
+
The runtime layer holds a positional `<%N%>` slot plus the variable id; the designer layer holds
|
|
305
|
+
the bare variable id. A node whose Output was never bound gets a fresh slot placed past every
|
|
306
|
+
`@param` bind index, because the engine resolves those slots positionally and a collision hands
|
|
307
|
+
the query the wrong value. Returns (changed, message).
|
|
308
|
+
"""
|
|
309
|
+
family, legacy = family_of(node)
|
|
310
|
+
if legacy:
|
|
311
|
+
return False, ("node is on a deprecated template (%s) - run sql-parameterize first"
|
|
312
|
+
% node.get("templateId"))
|
|
313
|
+
pid = _CURRENT[family]["output"]
|
|
314
|
+
|
|
315
|
+
param = next((p for p in node.get("parameters") or [] if p.get("tabPropertyId") == pid), None)
|
|
316
|
+
if param is None:
|
|
317
|
+
return False, "no Output parameter (%s) found on the node" % pid
|
|
318
|
+
|
|
319
|
+
bound = param.get("variable") or []
|
|
320
|
+
if bound and bound[0].get("variableId") == variable_id:
|
|
321
|
+
return False, "Output is already bound to %s" % variable_id
|
|
322
|
+
|
|
323
|
+
if bound:
|
|
324
|
+
bound[0]["variableId"] = variable_id
|
|
325
|
+
bound[0]["attribute"] = None
|
|
326
|
+
else:
|
|
327
|
+
slot = _next_slot(node)
|
|
328
|
+
param["variable"] = [{"id": slot, "variableId": variable_id, "attribute": None}]
|
|
329
|
+
param["value"] = "<%%%d%%>" % slot
|
|
330
|
+
|
|
331
|
+
for setting in _output_settings(node, pid):
|
|
332
|
+
setting["value"] = variable_id
|
|
333
|
+
|
|
334
|
+
return True, "Output rebound to %s" % variable_id
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def _next_slot(node: dict) -> int:
|
|
338
|
+
"""The first positional `<%N%>` index no parameter on this node already claims."""
|
|
339
|
+
used = {-1}
|
|
340
|
+
for prm in node.get("parameters") or []:
|
|
341
|
+
for ve in prm.get("variable") or []:
|
|
342
|
+
if isinstance(ve.get("id"), int):
|
|
343
|
+
used.add(ve["id"])
|
|
344
|
+
value = prm.get("value")
|
|
345
|
+
if isinstance(value, str):
|
|
346
|
+
used.update(int(m) for m in _PLACEHOLDER.findall(value))
|
|
347
|
+
elif isinstance(value, list):
|
|
348
|
+
for row in value:
|
|
349
|
+
if isinstance(row, dict) and isinstance(row.get("id"), int):
|
|
350
|
+
used.add(row["id"])
|
|
351
|
+
return max(used) + 1
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def _migrate_to_current(node: dict, query_param: dict, family: str, legacy: dict) -> None:
|
|
355
|
+
"""Move a node off a deprecated SQL template onto its family's current one, in place.
|
|
356
|
+
|
|
357
|
+
Purely a ROLE-BASED id remap driven by _LEGACY / _CURRENT: each legacy property id is looked up by
|
|
358
|
+
the role it plays (credentials, side-pannel, sql, timeout, output) and rewritten to the current
|
|
359
|
+
template's id for that same role, in both the runtime `parameters[]` and the designer customData.
|
|
360
|
+
A required Time Out the legacy template never had is seeded from `timeout_default`, so the
|
|
361
|
+
migration cannot hand the designer an empty required field.
|
|
362
|
+
"""
|
|
363
|
+
cur = _CURRENT[family]
|
|
364
|
+
remap = {legacy[role]: cur[role] for role in legacy if role in cur}
|
|
365
|
+
node["actionTemplateName"] = family
|
|
366
|
+
node["templateId"] = cur["templateId"]
|
|
367
|
+
|
|
368
|
+
for prm in node.get("parameters") or []:
|
|
369
|
+
pid = prm.get("tabPropertyId")
|
|
370
|
+
if pid in remap:
|
|
371
|
+
prm["tabPropertyId"] = remap[pid]
|
|
372
|
+
# the SQL param is authoritative even if the table missed it (unknown legacy layout)
|
|
373
|
+
query_param["tabPropertyId"] = cur["sql"]
|
|
374
|
+
|
|
375
|
+
for cfg in (node.get("customData") or {}).get("configuration") or []:
|
|
376
|
+
for setting in cfg.get("settings") or []:
|
|
377
|
+
if setting.get("id") in remap:
|
|
378
|
+
setting["id"] = remap[setting["id"]]
|
|
379
|
+
_relabel(setting, cur)
|
|
380
|
+
if isinstance(setting.get("value"), list):
|
|
381
|
+
for sub in setting["value"]:
|
|
382
|
+
if isinstance(sub, dict):
|
|
383
|
+
if sub.get("id") in remap:
|
|
384
|
+
sub["id"] = remap[sub["id"]]
|
|
385
|
+
_relabel(sub, cur)
|
|
386
|
+
|
|
387
|
+
default = cur.get("timeout_default")
|
|
388
|
+
if default and cur.get("timeout"):
|
|
389
|
+
_ensure_setting(node, cur["timeout"], cur["sidepanel"], "Time Out", "number", default)
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def _relabel(setting: dict, cur: dict) -> None:
|
|
393
|
+
"""Give a remapped setting the CURRENT template's wording; a stale label on a property that now
|
|
394
|
+
belongs to a different template is how the next reader concludes the migration did not happen."""
|
|
395
|
+
label = (cur.get("labels") or {}).get(setting.get("id"))
|
|
396
|
+
if label:
|
|
397
|
+
setting["label"] = label
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
def _ensure_setting(node: dict, pid: str, sidepanel_pid: str, label: str, stype: str, value) -> None:
|
|
401
|
+
"""Add a required property the legacy template did not carry, to BOTH layers, if it is absent."""
|
|
402
|
+
params = node.setdefault("parameters", [])
|
|
403
|
+
if not any(p.get("tabPropertyId") == pid for p in params):
|
|
404
|
+
params.append({"tabPropertyId": pid, "variable": [], "value": value})
|
|
405
|
+
for cfg in (node.get("customData") or {}).get("configuration") or []:
|
|
406
|
+
for setting in cfg.get("settings") or []:
|
|
407
|
+
if setting.get("id") == sidepanel_pid and isinstance(setting.get("value"), list):
|
|
408
|
+
if not any(isinstance(s, dict) and s.get("id") == pid for s in setting["value"]):
|
|
409
|
+
setting["value"].append({"id": pid, "dataTypeId": None, "label": label,
|
|
410
|
+
"type": stype, "value": value})
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Which form-code-key a call uses: one per PROCESIO installation.
|
|
2
|
+
|
|
3
|
+
A form's "Switch to code" CSS and JavaScript (`Data.code`) is AES-encrypted with a
|
|
4
|
+
passphrase the installation's web app holds. The platform team confirmed (2026-10-01)
|
|
5
|
+
that there is one key per INSTALLATION: identical on every workspace of it, and not
|
|
6
|
+
guaranteed to match on another. In this tool an installation is an environment
|
|
7
|
+
(environments.py), so the key is stored per environment:
|
|
8
|
+
|
|
9
|
+
agents-and-tools:procesio:form-code-key@<environment> e.g. form-code-key@Internal-QA
|
|
10
|
+
|
|
11
|
+
The bare `form-code-key` predates that and keeps working for the DEFAULT environment,
|
|
12
|
+
the same rule an unbound credential profile follows (environments.resolve). It is never
|
|
13
|
+
used for any other environment: a blob encrypted with another installation's key is one
|
|
14
|
+
that installation's renderer cannot open, and the form goes blank
|
|
15
|
+
(FORM-DEV-GUIDE/08-PITFALLS.md). A missing key is an error naming the exact secret to
|
|
16
|
+
store, never a silent fallback.
|
|
17
|
+
"""
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from tools.procesio.errors import UsageError
|
|
21
|
+
|
|
22
|
+
TOOL = "procesio"
|
|
23
|
+
LEGACY = "form-code-key"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def secret_name(env_name: str) -> str:
|
|
27
|
+
"""The Credential Manager secret holding `env_name`'s key."""
|
|
28
|
+
return f"{LEGACY}@{env_name}"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def key_for(env_name: str | None) -> str:
|
|
32
|
+
"""The form-code-key for `env_name` (None means the default environment)."""
|
|
33
|
+
from tools._lib import creds # lazy: avoid the keyring import unless needed
|
|
34
|
+
from tools.procesio import environments
|
|
35
|
+
|
|
36
|
+
default = environments.get_default()
|
|
37
|
+
env = (environments.canonical_name(env_name) or env_name) if env_name else default
|
|
38
|
+
key = creds.get_optional(TOOL, secret_name(env))
|
|
39
|
+
if key:
|
|
40
|
+
return key
|
|
41
|
+
if env == default:
|
|
42
|
+
key = creds.get_optional(TOOL, LEGACY)
|
|
43
|
+
if key:
|
|
44
|
+
return key
|
|
45
|
+
other = (f" The bare {LEGACY} is the default environment's key ({default}) and is "
|
|
46
|
+
f"never used for another installation." if env != default else "")
|
|
47
|
+
raise UsageError(
|
|
48
|
+
f"no form-code-key stored for environment {env}: the AES passphrase that "
|
|
49
|
+
f"installation uses for a form's Data.code. Store it with: python "
|
|
50
|
+
f"scripts/set-credential.py {TOOL} {secret_name(env)}.{other}")
|