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,256 @@
|
|
|
1
|
+
"""Adding a control to a LIVE form (flowmodel-free: dto/form/addelement).
|
|
2
|
+
|
|
3
|
+
Why this exists: `form-create` speaks an authoring config, `form-edit` rebuilds a form from one, and
|
|
4
|
+
neither can add a control to a form that was hand-built in the designer — the two shapes are
|
|
5
|
+
different languages (the create config has no element ids at all). Everything else in the toolkit is
|
|
6
|
+
surgical (set one config, wire one event); adding a control was the missing verb, so a new admin
|
|
7
|
+
button meant hand-writing a stored element DTO.
|
|
8
|
+
|
|
9
|
+
The invariant that makes it safe: PROCESIO backs every control with a data-model sub-model whose id
|
|
10
|
+
is the ELEMENT id and whose attribute ids are the ELEMENT'S OWN CONFIG IDS. So new controls can be
|
|
11
|
+
SPLICED into the live `Data.dataModel` without touching what is already there — which matters,
|
|
12
|
+
because a RUN_PROCESS map references a field by the path `root.fields.elementId.valueAttrId`, and
|
|
13
|
+
regenerating those ids would break every existing mapping on the form.
|
|
14
|
+
"""
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import copy
|
|
18
|
+
|
|
19
|
+
import pytest
|
|
20
|
+
|
|
21
|
+
from tools.procesio.dto.form import addelement
|
|
22
|
+
from tools.procesio.errors import UsageError
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
ROOT = "65396456-36bf-4d9f-8d32-63a4a9e5c8c0"
|
|
26
|
+
FIELDS_NS = "11223344-5566-7788-99aa-aabbccddeeff"
|
|
27
|
+
EXISTING_EL = "aaaaaaaa-1111-1111-1111-111111111111"
|
|
28
|
+
EXISTING_CFG = "bbbbbbbb-2222-2222-2222-222222222222"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _live_form() -> dict:
|
|
32
|
+
"""A form as GET /api/FormTemplate/{id} returns it, with one existing control."""
|
|
33
|
+
return {
|
|
34
|
+
"id": "form-1", "name": "Admin", "isPrivate": True, "type": 1, "status": 1,
|
|
35
|
+
"state": True, "assignees": [], "customUrl": None,
|
|
36
|
+
"data": {
|
|
37
|
+
"elements": [
|
|
38
|
+
{"id": EXISTING_EL, "type": "input", "section": "body", "parentId": None,
|
|
39
|
+
"category": "field",
|
|
40
|
+
"configs": [{"id": EXISTING_CFG, "key": "value", "label": "Value", "value": ""},
|
|
41
|
+
{"id": "cccccccc-3333-3333-3333-333333333333", "key": "name",
|
|
42
|
+
"label": "Name", "value": "DefaultTimeZone"}]},
|
|
43
|
+
],
|
|
44
|
+
"variables": [{"id": ROOT, "dataType": ROOT, "name": "form", "type": 20}],
|
|
45
|
+
"dataModel": {
|
|
46
|
+
"id": ROOT, "name": "form", "attributes": [
|
|
47
|
+
{"id": FIELDS_NS, "dataTypeId": FIELDS_NS, "name": "fields",
|
|
48
|
+
"parentDataTypeId": ROOT, "isDataModel": True, "attributes": [
|
|
49
|
+
{"id": EXISTING_EL, "dataTypeId": EXISTING_EL, "name": "DefaultTimeZone",
|
|
50
|
+
"parentDataTypeId": FIELDS_NS, "isDataModel": True, "attributes": [
|
|
51
|
+
{"id": EXISTING_CFG, "name": "value", "parentDataTypeId": EXISTING_EL}]},
|
|
52
|
+
]},
|
|
53
|
+
]},
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _fields_attrs(data: dict) -> list:
|
|
59
|
+
fields = next(a for a in data["dataModel"]["attributes"] if a["id"] == FIELDS_NS)
|
|
60
|
+
return fields["attributes"]
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _by_name(elements: list, name: str):
|
|
64
|
+
for el in elements:
|
|
65
|
+
for c in el.get("configs", []):
|
|
66
|
+
if c.get("key") == "name" and c.get("value") == name:
|
|
67
|
+
return el
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# --------------------------------------------------------------------------- the happy path
|
|
72
|
+
|
|
73
|
+
def test_a_new_control_is_appended_to_the_elements_list():
|
|
74
|
+
form = _live_form()
|
|
75
|
+
out = addelement.add_elements(form, [{"type": "input", "label": "Organiser Email",
|
|
76
|
+
"name": "OrganiserEmail"}])
|
|
77
|
+
|
|
78
|
+
assert len(out["elements"]) == 2
|
|
79
|
+
added = _by_name(out["elements"], "OrganiserEmail")
|
|
80
|
+
assert added is not None and added["type"] == "input"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_the_existing_control_is_untouched_down_to_its_config_ids():
|
|
84
|
+
form = _live_form()
|
|
85
|
+
before = copy.deepcopy(form["data"]["elements"][0])
|
|
86
|
+
|
|
87
|
+
out = addelement.add_elements(form, [{"type": "input", "name": "OrganiserEmail"}])
|
|
88
|
+
|
|
89
|
+
assert out["elements"][0] == before
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_every_existing_data_model_id_survives():
|
|
93
|
+
"""A RUN_PROCESS map references root.fields.elementId.valueAttrId — regenerating any of those
|
|
94
|
+
ids silently breaks every mapping already on the form."""
|
|
95
|
+
form = _live_form()
|
|
96
|
+
out = addelement.add_elements(form, [{"type": "input", "name": "OrganiserEmail"}])
|
|
97
|
+
|
|
98
|
+
existing = next(s for s in _fields_attrs(out) if s["id"] == EXISTING_EL)
|
|
99
|
+
assert existing["attributes"][0]["id"] == EXISTING_CFG
|
|
100
|
+
assert out["dataModel"]["id"] == ROOT
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def test_the_new_control_gets_a_sub_model_keyed_by_its_element_id():
|
|
104
|
+
form = _live_form()
|
|
105
|
+
out = addelement.add_elements(form, [{"type": "input", "name": "OrganiserEmail"}])
|
|
106
|
+
|
|
107
|
+
added = _by_name(out["elements"], "OrganiserEmail")
|
|
108
|
+
sub = next((s for s in _fields_attrs(out) if s["id"] == added["id"]), None)
|
|
109
|
+
assert sub is not None
|
|
110
|
+
assert sub["name"] == "OrganiserEmail"
|
|
111
|
+
assert sub["parentDataTypeId"] == FIELDS_NS
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def test_the_new_sub_model_attribute_ids_equal_the_new_element_config_ids():
|
|
115
|
+
form = _live_form()
|
|
116
|
+
out = addelement.add_elements(form, [{"type": "input", "name": "OrganiserEmail"}])
|
|
117
|
+
|
|
118
|
+
added = _by_name(out["elements"], "OrganiserEmail")
|
|
119
|
+
sub = next(s for s in _fields_attrs(out) if s["id"] == added["id"])
|
|
120
|
+
cfg_ids = {c["id"] for c in added["configs"]}
|
|
121
|
+
assert {a["id"] for a in sub["attributes"]} <= cfg_ids
|
|
122
|
+
assert any(a["name"] == "value" for a in sub["attributes"]), (
|
|
123
|
+
"the value attribute is what a process map binds to")
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# --------------------------------------------------------------------------- placement
|
|
127
|
+
|
|
128
|
+
def test_a_control_can_be_parented_to_an_existing_container():
|
|
129
|
+
form = _live_form()
|
|
130
|
+
form["data"]["elements"].append(
|
|
131
|
+
{"id": "tab-1", "type": "tab", "section": "body", "parentId": None,
|
|
132
|
+
"configs": [{"id": "n1", "key": "name", "value": "Tab1"}]})
|
|
133
|
+
|
|
134
|
+
out = addelement.add_elements(form, [{"type": "button", "label": "Delete", "name": "delBtn"}],
|
|
135
|
+
parent="Tab1")
|
|
136
|
+
|
|
137
|
+
assert _by_name(out["elements"], "delBtn")["parentId"] == "tab-1"
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def test_an_unknown_parent_is_refused_and_names_what_exists():
|
|
141
|
+
form = _live_form()
|
|
142
|
+
with pytest.raises(UsageError) as e:
|
|
143
|
+
addelement.add_elements(form, [{"type": "button", "name": "b"}], parent="Nope")
|
|
144
|
+
assert "Nope" in str(e.value)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def test_a_duplicate_control_name_is_refused():
|
|
148
|
+
"""Two controls sharing a name make the field-path resolver ambiguous."""
|
|
149
|
+
form = _live_form()
|
|
150
|
+
with pytest.raises(UsageError) as e:
|
|
151
|
+
addelement.add_elements(form, [{"type": "input", "name": "DefaultTimeZone"}])
|
|
152
|
+
assert "DefaultTimeZone" in str(e.value)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def test_several_controls_can_be_added_in_one_call_and_keep_their_order():
|
|
156
|
+
form = _live_form()
|
|
157
|
+
out = addelement.add_elements(form, [
|
|
158
|
+
{"type": "input", "name": "MinimumNoticeHours"},
|
|
159
|
+
{"type": "input", "name": "GoogleCalendarId"},
|
|
160
|
+
{"type": "input", "name": "OrganiserEmail"}])
|
|
161
|
+
|
|
162
|
+
names = [c["value"] for el in out["elements"] for c in el["configs"] if c["key"] == "name"]
|
|
163
|
+
assert names[-3:] == ["MinimumNoticeHours", "GoogleCalendarId", "OrganiserEmail"]
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def test_adding_nothing_is_refused_rather_than_writing_the_form_back_unchanged():
|
|
167
|
+
with pytest.raises(UsageError):
|
|
168
|
+
addelement.add_elements(_live_form(), [])
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def test_the_form_passed_in_is_not_mutated():
|
|
172
|
+
form = _live_form()
|
|
173
|
+
snapshot = copy.deepcopy(form)
|
|
174
|
+
addelement.add_elements(form, [{"type": "input", "name": "OrganiserEmail"}])
|
|
175
|
+
assert form == snapshot, "the caller decides when to write; the builder stays pure"
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
# --------------------------------------------------------------------------- container registration
|
|
179
|
+
|
|
180
|
+
def _form_with_tabs() -> dict:
|
|
181
|
+
"""A tabs container that draws its children from its own `tabs` list, as the runtime does."""
|
|
182
|
+
form = _live_form()
|
|
183
|
+
form["data"]["elements"].append(
|
|
184
|
+
{"id": "tabs-1", "type": "tabs", "section": "body", "parentId": None,
|
|
185
|
+
"configs": [{"id": "tn", "key": "name", "value": "Tabs1"},
|
|
186
|
+
{"id": "tl", "key": "tabs", "value": ["Tab1"]}]})
|
|
187
|
+
form["data"]["elements"].append(
|
|
188
|
+
{"id": "tab-1", "type": "tab", "section": "body", "parentId": "tabs-1",
|
|
189
|
+
"configs": [{"id": "t1n", "key": "name", "value": "Tab1"}]})
|
|
190
|
+
return form
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def test_a_new_tab_is_registered_in_its_container_list():
|
|
194
|
+
"""Parenting alone is not enough: a tabs container renders the names in its `tabs` config, so a
|
|
195
|
+
spliced tab that is missing from it exists, saves, lints clean and never appears on screen."""
|
|
196
|
+
out = addelement.add_elements(_form_with_tabs(), [{"type": "tab", "name": "Tab2"}],
|
|
197
|
+
parent="Tabs1")
|
|
198
|
+
tabs = next(e for e in out["elements"] if e["id"] == "tabs-1")
|
|
199
|
+
listed = next(c["value"] for c in tabs["configs"] if c["key"] == "tabs")
|
|
200
|
+
assert listed == ["Tab1", "Tab2"]
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def test_a_table_row_is_registered_in_the_table_rows_list():
|
|
204
|
+
form = _live_form()
|
|
205
|
+
form["data"]["elements"].append(
|
|
206
|
+
{"id": "table-1", "type": "table", "section": "body", "parentId": None,
|
|
207
|
+
"configs": [{"id": "tbn", "key": "name", "value": "Table1"},
|
|
208
|
+
{"id": "tbr", "key": "rows", "value": []}]})
|
|
209
|
+
out = addelement.add_elements(form, [{"type": "dynamic-table-row", "name": "Row1"}],
|
|
210
|
+
parent="Table1")
|
|
211
|
+
table = next(e for e in out["elements"] if e["id"] == "table-1")
|
|
212
|
+
assert next(c["value"] for c in table["configs"] if c["key"] == "rows") == ["Row1"]
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def test_a_container_with_no_list_config_is_untouched():
|
|
216
|
+
form = _live_form()
|
|
217
|
+
form["data"]["elements"].append(
|
|
218
|
+
{"id": "sec-1", "type": "section", "section": "body", "parentId": None,
|
|
219
|
+
"configs": [{"id": "sn", "key": "name", "value": "Section1"}]})
|
|
220
|
+
out = addelement.add_elements(form, [{"type": "input", "name": "Extra"}], parent="Section1")
|
|
221
|
+
sec = next(e for e in out["elements"] if e["id"] == "sec-1")
|
|
222
|
+
assert [c["key"] for c in sec["configs"]] == ["name"]
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def test_an_existing_entry_is_not_duplicated():
|
|
226
|
+
form = _form_with_tabs()
|
|
227
|
+
out = addelement.add_elements(form, [{"type": "tab", "name": "Tab2"}], parent="Tabs1")
|
|
228
|
+
form2 = {"id": "form-1", "data": out}
|
|
229
|
+
out2 = addelement.add_elements(form2, [{"type": "tab", "name": "Tab3"}], parent="Tabs1")
|
|
230
|
+
tabs = next(e for e in out2["elements"] if e["id"] == "tabs-1")
|
|
231
|
+
assert next(c["value"] for c in tabs["configs"] if c["key"] == "tabs") == ["Tab1", "Tab2", "Tab3"]
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def test_a_control_placed_inside_a_table_row_is_flagged_as_unreachable():
|
|
235
|
+
"""A map cannot read a control that exists once per row, and nothing else reports that."""
|
|
236
|
+
elements = [
|
|
237
|
+
{"id": "tbl", "type": "table", "parentId": None,
|
|
238
|
+
"configs": [{"key": "name", "value": "Table1"}, {"key": "rows", "value": ["Row1"]}]},
|
|
239
|
+
{"id": "row", "type": "dynamic-table-row", "parentId": "tbl",
|
|
240
|
+
"configs": [{"key": "name", "value": "Row1"}]},
|
|
241
|
+
{"id": "panel", "type": "side-panel", "parentId": "row",
|
|
242
|
+
"configs": [{"key": "name", "value": "EditPanel"}]},
|
|
243
|
+
]
|
|
244
|
+
warning = addelement.unreachable_in_row(elements, "panel")
|
|
245
|
+
assert warning is not None
|
|
246
|
+
assert "Row1" in warning
|
|
247
|
+
assert "$.item" in warning
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def test_a_control_outside_any_row_is_not_flagged():
|
|
251
|
+
elements = [
|
|
252
|
+
{"id": "tab", "type": "tab", "parentId": None,
|
|
253
|
+
"configs": [{"key": "name", "value": "Tab1"}]},
|
|
254
|
+
]
|
|
255
|
+
assert addelement.unreachable_in_row(elements, "tab") is None
|
|
256
|
+
assert addelement.unreachable_in_row(elements, None) is None
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
"""Three form gaps measured live on QA on 2026-09-25 while testing Approval Control events.
|
|
2
|
+
|
|
3
|
+
1. form-create left the top-level `Assignees` empty on a form whose section had an assignee
|
|
4
|
+
and whose approval control had an approver. The designer's save
|
|
5
|
+
(user-playground Builder.component.vue::save + ui-builder utils/formBuilder/payload.ts)
|
|
6
|
+
builds one ASSIGNEE step (type 1) per element with assignee users and one APPROVER step
|
|
7
|
+
(type 2) per element with approver users: `{stepId: <element id>, orderId: n, users:
|
|
8
|
+
[{userId}]}`, orderId counting 1, 2, 3 within each list.
|
|
9
|
+
2. form-create built a form data model with only `instance, fields` and no
|
|
10
|
+
`dataModelAttributeFormatVersion`. The designer writes `instance, flow, fields,
|
|
11
|
+
preventFormSubmit, browserTitle` and version "1" for a new form. Without the version the
|
|
12
|
+
designer treats the form as the legacy "0" format and LOWER-CASES every field attribute on
|
|
13
|
+
its next save (measured: `RequestText` became `requesttext`); without `preventFormSubmit`
|
|
14
|
+
a form script cannot block a submit.
|
|
15
|
+
3. form-set-element-event refused to wire an approval trigger on an approval control saved
|
|
16
|
+
before its event slots existed (old forms). The runtime back-fills missing configs from
|
|
17
|
+
the element template on every load (ui-builder utils/formBuilder/elements.ts::
|
|
18
|
+
actualizeElements); the CLI now does the same for the one slot it needs, and says so.
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import json
|
|
23
|
+
|
|
24
|
+
import pytest
|
|
25
|
+
|
|
26
|
+
from tools.procesio import main
|
|
27
|
+
from tools.procesio.client import ProcesioClient
|
|
28
|
+
from tools.procesio.dto.form import builder
|
|
29
|
+
from tools.procesio.errors import UsageError
|
|
30
|
+
from tools.procesio.tests.conftest import FakeResp, FakeSession
|
|
31
|
+
|
|
32
|
+
APIKEY = {"type": "apikey", "key": "N", "value": "V"}
|
|
33
|
+
U1, U2, U3 = "u-1111", "u-2222", "u-3333"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _call(action, argv, session):
|
|
37
|
+
return main.dispatch(
|
|
38
|
+
action, argv,
|
|
39
|
+
client_builder=lambda prof: ProcesioClient(profile=APIKEY, name="t", session=session))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _ids():
|
|
43
|
+
n = iter(range(10_000))
|
|
44
|
+
return {"new_id": lambda: f"id-{next(n)}"}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _by_type(dto, kind):
|
|
48
|
+
return [e for e in dto["Data"]["elements"] if e["type"] == kind]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# --------------------------------------------------------------------------- gap 1
|
|
52
|
+
|
|
53
|
+
def _approval_form(**top):
|
|
54
|
+
return {
|
|
55
|
+
"name": "AUTO approval gaps",
|
|
56
|
+
**top,
|
|
57
|
+
"elements": [
|
|
58
|
+
{"type": "section", "label": "Request", "configs": {"assignee": U1},
|
|
59
|
+
"children": [{"type": "input", "label": "Text", "name": "RequestText"}]},
|
|
60
|
+
{"type": "approval", "label": "Approval step", "name": "Approval1",
|
|
61
|
+
"approver": U2, "configs": {"approverReplacement": [U3, "", U2]}},
|
|
62
|
+
{"type": "button", "label": "Submit", "submit": True},
|
|
63
|
+
],
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_assignees_are_derived_from_assignee_and_approver_configs_like_the_designer():
|
|
68
|
+
dto = builder.build(_approval_form(isPrivate=True), _ids())
|
|
69
|
+
section, = _by_type(dto, "section")
|
|
70
|
+
approval, = _by_type(dto, "approval")
|
|
71
|
+
assert dto["Assignees"] == [
|
|
72
|
+
{"stepId": section["id"], "orderId": 1, "type": 1, "users": [{"userId": U1}]},
|
|
73
|
+
# approver first, then replacements; blanks dropped, duplicates collapsed
|
|
74
|
+
{"stepId": approval["id"], "orderId": 1, "type": 2,
|
|
75
|
+
"users": [{"userId": U2}, {"userId": U3}]},
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def test_order_ids_count_within_each_list():
|
|
80
|
+
cfg = _approval_form()
|
|
81
|
+
cfg["elements"].insert(2, {"type": "approval", "label": "Second", "name": "Approval2",
|
|
82
|
+
"approver": U3})
|
|
83
|
+
dto = builder.build(cfg, _ids())
|
|
84
|
+
approvers = [a for a in dto["Assignees"] if a["type"] == 2]
|
|
85
|
+
assert [a["orderId"] for a in approvers] == [1, 2]
|
|
86
|
+
assert [a["users"][0]["userId"] for a in approvers] == [U2, U3]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_a_form_with_approvers_becomes_a_user_task_when_type_is_not_given():
|
|
90
|
+
assert builder.build(_approval_form(), _ids())["Type"] == 0
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def test_an_explicit_type_is_respected():
|
|
94
|
+
assert builder.build(_approval_form(type="general"), _ids())["Type"] == 1
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_explicit_assignees_in_the_config_still_win_verbatim():
|
|
98
|
+
mine = [{"stepId": "S", "orderId": 7, "type": 2, "users": [{"userId": "X"}]}]
|
|
99
|
+
assert builder.build(_approval_form(assignees=mine), _ids())["Assignees"] == mine
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def test_a_form_without_assignees_is_unchanged():
|
|
103
|
+
dto = builder.build({"name": "plain", "elements": [{"type": "input", "label": "A"}]}, _ids())
|
|
104
|
+
assert dto["Assignees"] == [] and dto["Type"] == 1
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# --------------------------------------------------------------------------- gap 2
|
|
108
|
+
|
|
109
|
+
PREVENT = "d63722f4-0cd1-4bc2-8174-28276e7c7ab5"
|
|
110
|
+
TITLE = "b8c1f2a3-4d5e-4a6b-8c7d-9e0f1a2b3c4d"
|
|
111
|
+
FLOW = "c16e9d56-8484-444d-b1c5-36e48afb1d3d"
|
|
112
|
+
INSTANCE = "8b49c48a-0834-40d0-920a-4c53566495a8"
|
|
113
|
+
BOOL, STR = "0317bfee-b2f5-4bde-bfe8-121212121210", "0317bfee-b2f5-4bde-bfe8-121212121214"
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def test_data_model_matches_what_the_designer_saves_for_a_new_form():
|
|
117
|
+
dto = builder.build(_approval_form(), _ids())
|
|
118
|
+
data = dto["Data"]
|
|
119
|
+
assert data["dataModelAttributeFormatVersion"] == "1"
|
|
120
|
+
dm = data["dataModel"]
|
|
121
|
+
top = {a["name"]: a for a in dm["attributes"]}
|
|
122
|
+
assert [a["name"] for a in dm["attributes"]] == [
|
|
123
|
+
"instance", "flow", "fields", "preventFormSubmit", "browserTitle"]
|
|
124
|
+
root = data["variables"][0]["id"]
|
|
125
|
+
assert dm["id"] == root
|
|
126
|
+
assert all(a["parentDataTypeId"] == root for a in dm["attributes"])
|
|
127
|
+
assert (top["preventFormSubmit"]["id"], top["preventFormSubmit"]["dataTypeId"]) == (PREVENT, BOOL)
|
|
128
|
+
assert (top["browserTitle"]["id"], top["browserTitle"]["dataTypeId"]) == (TITLE, STR)
|
|
129
|
+
assert top["flow"]["id"] == FLOW and "statusEnum" in [a["name"] for a in top["flow"]["attributes"]]
|
|
130
|
+
assert top["instance"]["id"] == INSTANCE
|
|
131
|
+
assert [a["name"] for a in top["instance"]["attributes"]] == [
|
|
132
|
+
"id", "workspaceId", "submitter", "currentUser"]
|
|
133
|
+
# the fields container still carries one sub-model per element, named as-is (format "1")
|
|
134
|
+
assert "RequestText" in [a["name"] for a in top["fields"]["attributes"]]
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
# --------------------------------------------------------------------------- gap 3
|
|
138
|
+
|
|
139
|
+
def _old_form():
|
|
140
|
+
"""An approval control as saved before its event slots existed (QA form 8d789e26…,
|
|
141
|
+
created 2025-06-03): 15 configs, no onBefore*/onAfter* keys."""
|
|
142
|
+
old_keys = ["label", "tooltip", "description", "info-text", "visible", "comment",
|
|
143
|
+
"responseDate", "responseUser", "response", "name", "id", "approver",
|
|
144
|
+
"approverReplacement", "additionalApprovers", "onInputEvents"]
|
|
145
|
+
configs = [{"id": f"c-{k}", "key": k, "value": None} for k in old_keys]
|
|
146
|
+
next(c for c in configs if c["key"] == "name")["value"] = "Approval1"
|
|
147
|
+
return {
|
|
148
|
+
"id": "F-OLD", "name": "Complex (Copy)", "isPrivate": True, "type": 0, "status": 1,
|
|
149
|
+
"state": True, "assignees": [], "customUrl": None,
|
|
150
|
+
"data": {"code": "", "dataModel": {"id": "dm"}, "elements": [
|
|
151
|
+
{"id": "A1", "type": "approval", "configs": configs},
|
|
152
|
+
{"id": "I1", "type": "input", "configs": [{"id": "c-n", "key": "name", "value": "Input1"}]},
|
|
153
|
+
]},
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
_JS = {"code": "console.log($event)"}
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def test_a_missing_approval_slot_is_backfilled_from_the_template_and_reported():
|
|
161
|
+
s = FakeSession(queue=[FakeResp(200, _old_form()), FakeResp(200, _old_form()), FakeResp(200, {})])
|
|
162
|
+
out = _call("form-set-element-event",
|
|
163
|
+
["--id", "F-OLD", "--element", "Approval1", "--on", "beforeapprove",
|
|
164
|
+
"--action", "RUN_JAVASCRIPT", "--config", json.dumps(_JS)], s)
|
|
165
|
+
|
|
166
|
+
assert out["updated"] is True
|
|
167
|
+
assert out["backfilled"] == ["onBeforeApproveEvents"]
|
|
168
|
+
put = s.calls[-1]
|
|
169
|
+
assert put["method"] == "PUT"
|
|
170
|
+
els = put["json"]["Data"]["elements"]
|
|
171
|
+
assert els[1] == _old_form()["data"]["elements"][1] # sibling untouched
|
|
172
|
+
configs = els[0]["configs"]
|
|
173
|
+
slot = [c for c in configs if c["key"] == "onBeforeApproveEvents"]
|
|
174
|
+
assert len(slot) == 1
|
|
175
|
+
assert slot[0]["type"] == "field-events" and slot[0]["id"] not in {c.get("id") for c in _old_form()["data"]["elements"][0]["configs"]}
|
|
176
|
+
assert slot[0]["value"]["events"][0]["type"] == "BEFORE_APPROVE"
|
|
177
|
+
# every existing config survives, in its original order
|
|
178
|
+
assert [c for c in configs if c["key"] != "onBeforeApproveEvents"] == _old_form()["data"]["elements"][0]["configs"]
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def test_dry_run_reports_the_backfill_without_writing():
|
|
182
|
+
s = FakeSession(queue=[FakeResp(200, _old_form())])
|
|
183
|
+
out = _call("form-set-element-event",
|
|
184
|
+
["--id", "F-OLD", "--element", "Approval1", "--on", "afterapprovalsubmit",
|
|
185
|
+
"--action", "RUN_JAVASCRIPT", "--config", json.dumps(_JS), "--dry-run"], s)
|
|
186
|
+
assert out["dry_run"] is True and out["backfilled"] == ["onAfterApprovalSubmitEvents"]
|
|
187
|
+
assert all(c["method"] == "GET" for c in s.calls)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def test_a_trigger_the_element_type_cannot_raise_is_still_refused():
|
|
191
|
+
s = FakeSession(queue=[FakeResp(200, _old_form())])
|
|
192
|
+
with pytest.raises(UsageError, match="cannot raise"):
|
|
193
|
+
_call("form-set-element-event",
|
|
194
|
+
["--id", "F-OLD", "--element", "Input1", "--on", "beforeapprove",
|
|
195
|
+
"--action", "RUN_JAVASCRIPT", "--config", json.dumps(_JS)], s)
|
|
196
|
+
assert all(c["method"] == "GET" for c in s.calls)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def test_an_existing_slot_is_used_as_is_and_nothing_is_reported_as_backfilled():
|
|
200
|
+
s = FakeSession(queue=[FakeResp(200, _old_form()), FakeResp(200, _old_form()), FakeResp(200, {})])
|
|
201
|
+
out = _call("form-set-element-event",
|
|
202
|
+
["--id", "F-OLD", "--element", "Approval1", "--on", "input",
|
|
203
|
+
"--action", "RUN_JAVASCRIPT", "--config", json.dumps(_JS)], s)
|
|
204
|
+
assert out["backfilled"] == []
|
|
205
|
+
configs = s.calls[-1]["json"]["Data"]["elements"][0]["configs"]
|
|
206
|
+
assert len(configs) == len(_old_form()["data"]["elements"][0]["configs"])
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
# --------------------------------------------------------------- dynamic-row approval steps
|
|
210
|
+
# Shape of a real designer-saved "Dynamic Table Approval" form (QA, ids replaced): approval
|
|
211
|
+
# steps live in each dynamic row's `approvalSteps`, and each step is its own APPROVER step.
|
|
212
|
+
|
|
213
|
+
def _cfg_el(eid, etype, parent=None, **configs):
|
|
214
|
+
return {"id": eid, "type": etype, "parentId": parent,
|
|
215
|
+
"configs": [{"key": k, "value": v} for k, v in configs.items()]}
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def _step(sid, approver, replacement=None, row_index="0"):
|
|
219
|
+
return {"id": sid, "rowIndex": row_index, "approver": approver,
|
|
220
|
+
"approverReplacement": replacement or []}
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _table_form():
|
|
224
|
+
return [
|
|
225
|
+
_cfg_el("SEC", "section", assignee=U1),
|
|
226
|
+
_cfg_el("T", "table", assignee=U2),
|
|
227
|
+
_cfg_el("R1", "dynamic-table-row", "T", visible=True, approvalSteps=[
|
|
228
|
+
_step("S1", U1), _step("S2", U2, [U3, U2]),
|
|
229
|
+
_step("S-UNPLACED", U3, row_index=None)]), # no rowIndex: not a step
|
|
230
|
+
_cfg_el("R2", "dynamic-table-row", "T", visible=False, # hidden row: no steps
|
|
231
|
+
approvalSteps=[_step("S-HIDDEN", U1)]),
|
|
232
|
+
_cfg_el("R3", "dynamic-table-row", "SEC", # not in a table: no steps
|
|
233
|
+
approvalSteps=[_step("S-ORPHAN", U1)]),
|
|
234
|
+
_cfg_el("A", "approval", approver=U3),
|
|
235
|
+
]
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def test_dynamic_row_approval_steps_are_their_own_steps_like_the_designer():
|
|
239
|
+
rows = builder.derive_assignees(_table_form())
|
|
240
|
+
assert [(r["type"], r["stepId"], r["orderId"], [u["userId"] for u in r["users"]])
|
|
241
|
+
for r in rows] == [
|
|
242
|
+
(1, "SEC", 1, [U1]), (1, "T", 2, [U2]),
|
|
243
|
+
(2, "S1", 1, [U1]), (2, "S2", 2, [U2, U3]), (2, "A", 3, [U3]),
|
|
244
|
+
]
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
# --------------------------------------------------------------- surgical edits keep routing true
|
|
248
|
+
|
|
249
|
+
def test_an_edit_that_does_not_change_routing_keeps_the_stored_list_byte_for_byte():
|
|
250
|
+
stale = [{"stepId": "whatever", "orderId": 9, "type": 2, "users": [{"userId": "x"}]}]
|
|
251
|
+
before = [_cfg_el("A", "approval", approver=U1, label="Old")]
|
|
252
|
+
after = [_cfg_el("A", "approval", approver=U1, label="New")]
|
|
253
|
+
assert builder.reconcile_assignees(stale, before, after) == (stale, None)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def test_an_edit_that_changes_routing_rederives_the_whole_list():
|
|
257
|
+
before = [_cfg_el("A", "approval", approver=U1)]
|
|
258
|
+
after = [_cfg_el("A", "approval", approver=U2)]
|
|
259
|
+
saved, report = builder.reconcile_assignees([], before, after)
|
|
260
|
+
assert saved == [{"stepId": "A", "orderId": 1, "type": 2, "users": [{"userId": U2}]}]
|
|
261
|
+
assert report["rederived"] is True and report["after"] == [("A", 1, 2, (U2,))]
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def _live_approval_form(**top):
|
|
265
|
+
approver = {"id": "c-appr", "key": "approver", "value": U1}
|
|
266
|
+
return {
|
|
267
|
+
"id": "F-LIVE", "name": "Live", "isPrivate": True, "type": 0, "status": 1, "state": True,
|
|
268
|
+
"customUrl": None,
|
|
269
|
+
"assignees": [{"stepId": "A1", "orderId": 1, "type": 2,
|
|
270
|
+
"users": [{"userId": U1, "firstName": "G", "lastName": "G"}]}],
|
|
271
|
+
"data": {
|
|
272
|
+
"code": "", "variables": [{"id": "root", "dataType": "root", "name": "form"}],
|
|
273
|
+
"dataModel": {"id": "root", "name": "form", "attributes": [
|
|
274
|
+
{"id": "11223344-5566-7788-99aa-aabbccddeeff", "name": "fields",
|
|
275
|
+
"parentDataTypeId": "root", "attributes": []}]},
|
|
276
|
+
"elements": [
|
|
277
|
+
{"id": "A1", "type": "approval", "parentId": None, "section": "body",
|
|
278
|
+
"configs": [{"id": "c-name", "key": "name", "value": "Approval1"},
|
|
279
|
+
{"id": "c-label", "key": "label", "value": "Approve"}, approver]},
|
|
280
|
+
]},
|
|
281
|
+
**top,
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def test_set_element_config_rederives_assignees_when_the_approver_changes():
|
|
286
|
+
s = FakeSession(queue=[FakeResp(200, _live_approval_form()), FakeResp(200, {})])
|
|
287
|
+
out = _call("form-set-element-config",
|
|
288
|
+
["--id", "F-LIVE", "--element", "Approval1", "--set", f"approver={U2}"], s)
|
|
289
|
+
put = s.calls[-1]["json"]
|
|
290
|
+
assert put["Assignees"] == [{"stepId": "A1", "orderId": 1, "type": 2, "users": [{"userId": U2}]}]
|
|
291
|
+
assert out["assignees"]["rederived"] is True
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def test_set_element_config_leaves_assignees_alone_for_a_label_change():
|
|
295
|
+
s = FakeSession(queue=[FakeResp(200, _live_approval_form()), FakeResp(200, {})])
|
|
296
|
+
out = _call("form-set-element-config",
|
|
297
|
+
["--id", "F-LIVE", "--element", "Approval1", "--set", "label=Check"], s)
|
|
298
|
+
assert s.calls[-1]["json"]["Assignees"] == _live_approval_form()["assignees"] # echoed
|
|
299
|
+
assert "assignees" not in out
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def test_add_element_routes_a_new_approval_control():
|
|
303
|
+
s = FakeSession(queue=[FakeResp(200, _live_approval_form()), FakeResp(200, {})])
|
|
304
|
+
spec = {"type": "approval", "name": "Approval2", "approver": U3}
|
|
305
|
+
out = _call("form-add-element", ["--id", "F-LIVE", "--elements", json.dumps(spec)], s)
|
|
306
|
+
put = s.calls[-1]["json"]
|
|
307
|
+
new_id = out["added"][0]["id"]
|
|
308
|
+
assert put["Assignees"] == [
|
|
309
|
+
{"stepId": "A1", "orderId": 1, "type": 2, "users": [{"userId": U1}]},
|
|
310
|
+
{"stepId": new_id, "orderId": 2, "type": 2, "users": [{"userId": U3}]},
|
|
311
|
+
]
|
|
312
|
+
assert out["assignees"]["rederived"] is True
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def test_delete_element_unroutes_a_removed_approval_control():
|
|
316
|
+
s = FakeSession(queue=[FakeResp(200, _live_approval_form()), FakeResp(200, {})])
|
|
317
|
+
out = _call("form-delete-element", ["--id", "F-LIVE", "--element", "Approval1"], s)
|
|
318
|
+
assert s.calls[-1]["json"]["Assignees"] == []
|
|
319
|
+
assert out["assignees"]["rederived"] is True
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Auto-generated field names are single lowercase words, stable across a designer save.
|
|
2
|
+
|
|
3
|
+
When a form config gives no explicit `name`, the builder derives one from the label. It
|
|
4
|
+
used to title-case it (`Company Name` -> `CompanyName`), which a designer save re-keys and
|
|
5
|
+
`formlint.lint_field_names` then flags. The builder now makes a single lowercase word, so
|
|
6
|
+
an auto-named field survives a designer save unchanged and does not trip the lint. The
|
|
7
|
+
human-readable text stays in the label, not the name. `_slug` (flowgraph display, which
|
|
8
|
+
keeps case) is a different function and is left alone.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import itertools
|
|
13
|
+
|
|
14
|
+
from tools.procesio import formlint
|
|
15
|
+
from tools.procesio.dto.form import builder as fb
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _ctx():
|
|
19
|
+
cnt = itertools.count(1)
|
|
20
|
+
return {"new_id": lambda: f"00000000-0000-0000-0000-{next(cnt):012d}"}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_field_slug_is_a_single_lowercase_word():
|
|
24
|
+
assert fb._field_slug("Company Name") == "companyname"
|
|
25
|
+
assert fb._field_slug("order_id") == "orderid"
|
|
26
|
+
assert fb._field_slug("Already lower") == "alreadylower"
|
|
27
|
+
assert fb._field_slug("") == "field"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_unnamed_elements_get_lowercase_names_that_do_not_trip_the_lint():
|
|
31
|
+
dto = fb.build({"name": "F", "elements": [
|
|
32
|
+
{"type": "input", "label": "Company Name"},
|
|
33
|
+
{"type": "select", "label": "Order List", "options": ["a", "b"]},
|
|
34
|
+
]}, _ctx())
|
|
35
|
+
data = dto["Data"]
|
|
36
|
+
names = [c["value"] for e in data["elements"] for c in e.get("configs", [])
|
|
37
|
+
if c.get("key") == "name"]
|
|
38
|
+
assert "companyname" in names and "orderlist" in names, names
|
|
39
|
+
assert all(fb._SINGLE_WORD.fullmatch(n) for n in names) if hasattr(fb, "_SINGLE_WORD") \
|
|
40
|
+
else all(n == n.lower() and n.isalnum() for n in names), names
|
|
41
|
+
assert formlint.lint_field_names(data) == []
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_an_explicit_mixed_case_name_is_left_as_written():
|
|
45
|
+
"""Kept verbatim. Since 2026-10-05 the builder writes dataModelAttributeFormatVersion "1",
|
|
46
|
+
and a designer save keeps names at "1" (measured on QA: orderList, order_id and
|
|
47
|
+
Customer_First_Name survived a designer re-publish and form JS saw them as written), so a
|
|
48
|
+
builder-made form draws no warning. The same names on a form WITHOUT the version (legacy
|
|
49
|
+
"0", e.g. one built before that date) still warn."""
|
|
50
|
+
dto = fb.build({"name": "F", "elements": [
|
|
51
|
+
{"type": "input", "label": "x", "name": "OrderList"},
|
|
52
|
+
]}, _ctx())
|
|
53
|
+
data = dto["Data"]
|
|
54
|
+
names = [c["value"] for e in data["elements"] for c in e.get("configs", [])
|
|
55
|
+
if c.get("key") == "name"]
|
|
56
|
+
assert "OrderList" in names, names
|
|
57
|
+
assert data["dataModelAttributeFormatVersion"] == "1"
|
|
58
|
+
assert formlint.lint_field_names(data) == []
|
|
59
|
+
legacy = {k: v for k, v in data.items() if k != "dataModelAttributeFormatVersion"}
|
|
60
|
+
assert formlint.lint_field_names(legacy), "a form without the version must still warn"
|