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,1018 @@
|
|
|
1
|
+
"""Surgical node-parameter read/write on a LIVE process.
|
|
2
|
+
|
|
3
|
+
node-params list a process's nodes (or one node) with each runtime parameter's designer label,
|
|
4
|
+
current value and bound variables — read-only.
|
|
5
|
+
node-set-param set ONE parameter's literal text on ONE node -> regenerate the designer layer from
|
|
6
|
+
the runtime layer (normalizer) -> BE validate + designer flow-lint -> PUT.
|
|
7
|
+
--dry-run patches + validates but never PUTs; an invalid flow is never PUT.
|
|
8
|
+
node-replace-text replace an EXACT literal in every string leaf of a node's runtime parameters AND
|
|
9
|
+
designer settings — the safe way to reach a value nested inside a structured
|
|
10
|
+
parameter (a Map Data row's expression, a decisional literal), which node-set-param
|
|
11
|
+
refuses and the normalizer cannot regenerate. Same validate -> lint -> PUT gate.
|
|
12
|
+
|
|
13
|
+
This is the safe path for "one literal moved" edits on a designer-built flow (an API endpoint whose
|
|
14
|
+
host changed, a timeout, a SQL statement, a script body), where a desired-state rebuild would risk
|
|
15
|
+
everything the config cannot express. Structured parameters stay builder territory — see
|
|
16
|
+
flowmodel/nodeparam.py. Never hand-write customData: the normalizer derives it (standing rule).
|
|
17
|
+
|
|
18
|
+
JSON in / JSON out; impure (live client). Thin wrappers over GET / validate / PUT /api/Projects.
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import argparse
|
|
23
|
+
import json
|
|
24
|
+
|
|
25
|
+
from tools.procesio.actiondef import ActionDef
|
|
26
|
+
from tools.procesio.client import VARIABLES_ONLY
|
|
27
|
+
from tools.procesio.dto.process.builder import fetch_datastore_meta, render_query_tokens
|
|
28
|
+
from tools.procesio.dto.process.normalize import normalize_designer_layer
|
|
29
|
+
from tools.procesio.errors import ProcesioAPIError, UsageError
|
|
30
|
+
from tools.procesio.flowmodel import nodeparam
|
|
31
|
+
from tools.procesio.handlers.common import add_profile_arg
|
|
32
|
+
from tools.procesio.handlers.fevalidate import run_fe_validation, save_flow
|
|
33
|
+
from tools.procesio.handlers.flowlint import _template_sidepanel_ids, lint_flow_dto
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _fetch_flow(client, pid: str) -> dict:
|
|
37
|
+
flow = client.get(f"/api/Projects/{pid}")
|
|
38
|
+
return flow.get("flow") if isinstance(flow, dict) and "flow" in flow else flow
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _validate(client, flow: dict):
|
|
42
|
+
"""(is_valid, errors). Empty 200 == valid (same oracle as process-validate / sql-parameterize)."""
|
|
43
|
+
try:
|
|
44
|
+
res = client.post("/api/Projects/validate", flow)
|
|
45
|
+
except ProcesioAPIError as e:
|
|
46
|
+
det = e.details if isinstance(e.details, dict) else {"body": e.details}
|
|
47
|
+
return False, det.get("body", det)
|
|
48
|
+
empty = (not res) or (isinstance(res, dict) and list(res.keys()) == ["raw_text"] and not res["raw_text"])
|
|
49
|
+
return (True, None) if empty else (False, res)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _lint(client, flow: dict) -> list[dict]:
|
|
53
|
+
try:
|
|
54
|
+
tmpl_sp = _template_sidepanel_ids(client)
|
|
55
|
+
except Exception: # noqa: BLE001 - catalog unreachable -> lint what does not need it
|
|
56
|
+
tmpl_sp = {}
|
|
57
|
+
|
|
58
|
+
def target_vars_of(fid: str) -> dict:
|
|
59
|
+
try:
|
|
60
|
+
r = client.get(f"/api/Projects/{fid}", VARIABLES_ONLY)
|
|
61
|
+
f = r.get("flow", r) if isinstance(r, dict) else r
|
|
62
|
+
return {v["id"]: v for v in f.get("variables") or []}
|
|
63
|
+
except Exception: # noqa: BLE001 - unreadable target -> can't assert its contract
|
|
64
|
+
return {}
|
|
65
|
+
return lint_flow_dto(flow, tmpl_sp, target_vars_of)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _gate_and_put(client, flow: dict, args, result: dict, *, block_on_lint: bool = True) -> dict:
|
|
70
|
+
"""The tail every surgical writer shares: validate, lint, then save or say why not.
|
|
71
|
+
|
|
72
|
+
One copy, because four call sites held drifted copies of it and a copy is where a
|
|
73
|
+
fix stops arriving. Two of them disagreed about whether a lint problem blocks.
|
|
74
|
+
|
|
75
|
+
`isValid` in the result is the STORED value re-read after the save, not the
|
|
76
|
+
pre-save measurement. The two differ: the platform keeps whatever the body carries,
|
|
77
|
+
so a flow that validates clean can still land on a process the server has marked
|
|
78
|
+
broken unless the mark is stamped. On the paths that write nothing (dry run,
|
|
79
|
+
blocked, invalid) there is no stored-after value, so it carries the verdict for the
|
|
80
|
+
patched flow instead - which is the question those paths are asked.
|
|
81
|
+
|
|
82
|
+
The blocking rule is unchanged: the runtime validator refuses the PUT, a designer
|
|
83
|
+
error does not. Saving a half-finished process is intended platform behaviour, and
|
|
84
|
+
the stamped mark is how the result stays honest about it.
|
|
85
|
+
"""
|
|
86
|
+
valid, errors = _validate(client, flow)
|
|
87
|
+
problems = _lint(client, flow)
|
|
88
|
+
result["lint_problems"] = problems
|
|
89
|
+
if not valid: # never PUT a flow the runtime validator rejects
|
|
90
|
+
result["isValid"] = False
|
|
91
|
+
result["errors"] = errors
|
|
92
|
+
result["put"] = False
|
|
93
|
+
return result
|
|
94
|
+
if block_on_lint:
|
|
95
|
+
blocking = [p for p in problems if p.get("kind") == "CUSTOMDATA_PLACEHOLDER"]
|
|
96
|
+
if blocking:
|
|
97
|
+
result["isValid"] = valid
|
|
98
|
+
result["put"] = False
|
|
99
|
+
result["blocked_by"] = blocking
|
|
100
|
+
return result
|
|
101
|
+
fe = run_fe_validation(client, flow)
|
|
102
|
+
result["fe"] = fe
|
|
103
|
+
if args.dry_run:
|
|
104
|
+
result["isValid"] = bool(valid and fe["clean"])
|
|
105
|
+
result["put"] = False
|
|
106
|
+
result["dry_run"] = True
|
|
107
|
+
return result
|
|
108
|
+
saved = save_flow(client, flow, flow_id=args.id, valid=valid and fe["clean"])
|
|
109
|
+
result["isValid"] = saved["isValid"]
|
|
110
|
+
result["stamped"] = saved["stamped"]
|
|
111
|
+
if "readback_error" in saved:
|
|
112
|
+
result["readback_error"] = saved["readback_error"]
|
|
113
|
+
result["put"] = True
|
|
114
|
+
return result
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def node_params(client, args) -> dict:
|
|
118
|
+
flow = _fetch_flow(client, args.id)
|
|
119
|
+
if args.node:
|
|
120
|
+
n = nodeparam.find_node(flow, args.node)
|
|
121
|
+
if not n:
|
|
122
|
+
raise UsageError(f"node not found in process {args.id}: {args.node}")
|
|
123
|
+
nodes = [nodeparam.describe_node(flow, n)]
|
|
124
|
+
else:
|
|
125
|
+
nodes = nodeparam.scan(flow)
|
|
126
|
+
return {"id": args.id, "title": flow.get("title"), "node_count": len(nodes), "nodes": nodes}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def node_set_param(client, args) -> dict:
|
|
130
|
+
if getattr(args, "value_file", None):
|
|
131
|
+
if args.value is not None:
|
|
132
|
+
raise UsageError("pass either --value or --value-file, not both")
|
|
133
|
+
import io as _io
|
|
134
|
+
args.value = _io.open(args.value_file, encoding="utf-8", newline="").read()
|
|
135
|
+
if args.value is None:
|
|
136
|
+
raise UsageError("nothing to set: pass --value or --value-file")
|
|
137
|
+
flow = _fetch_flow(client, args.id)
|
|
138
|
+
node = nodeparam.find_node(flow, args.node)
|
|
139
|
+
if not node:
|
|
140
|
+
raise UsageError(f"node not found in process {args.id}: {args.node}")
|
|
141
|
+
param = nodeparam.find_param(node, args.property)
|
|
142
|
+
if param is None:
|
|
143
|
+
raise UsageError(
|
|
144
|
+
f"property not found on node '{args.node}': {args.property} "
|
|
145
|
+
f"(run node-params --node '{args.node}' to list the labels)")
|
|
146
|
+
try:
|
|
147
|
+
change = nodeparam.set_param_value(node, param, args.value,
|
|
148
|
+
allow_binding_change=args.allow_binding_change)
|
|
149
|
+
except ValueError as e:
|
|
150
|
+
raise UsageError(str(e)) from e
|
|
151
|
+
|
|
152
|
+
result = {"id": args.id, "title": flow.get("title"), "node": node.get("actionName"),
|
|
153
|
+
"property": param.get("tabPropertyId"), **change}
|
|
154
|
+
if not change["changed"]:
|
|
155
|
+
result["note"] = "value already set; nothing to PUT"
|
|
156
|
+
result["put"] = False
|
|
157
|
+
return result
|
|
158
|
+
|
|
159
|
+
result["normalized"] = normalize_designer_layer(flow)
|
|
160
|
+
return _gate_and_put(client, flow, args, result)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def node_delete(client, args) -> dict:
|
|
164
|
+
flow = _fetch_flow(client, args.id)
|
|
165
|
+
node = nodeparam.find_node(flow, args.node)
|
|
166
|
+
if not node:
|
|
167
|
+
raise UsageError(f"node not found in process {args.id}: {args.node}")
|
|
168
|
+
|
|
169
|
+
changed, msg = nodeparam.delete_node(flow, node)
|
|
170
|
+
result = {"id": args.id, "title": flow.get("title"), "node": node.get("actionName"),
|
|
171
|
+
"node_id": node.get("id"), "deleted": changed, "msg": msg}
|
|
172
|
+
if not changed:
|
|
173
|
+
result["put"] = False
|
|
174
|
+
return result
|
|
175
|
+
|
|
176
|
+
return _gate_and_put(client, flow, args, result)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def node_replace_text(client, args) -> dict:
|
|
180
|
+
flow = _fetch_flow(client, args.id)
|
|
181
|
+
node = nodeparam.find_node(flow, args.node)
|
|
182
|
+
if not node:
|
|
183
|
+
raise UsageError(f"node not found in process {args.id}: {args.node}")
|
|
184
|
+
if not args.allow_binding_change and ("<%" in args.find or "<%" in args.replace):
|
|
185
|
+
raise UsageError(
|
|
186
|
+
"--find/--replace touch a <%N%> placeholder, which binds variable[] positionally; "
|
|
187
|
+
"pass --allow-binding-change only when variable[] is being rewritten too")
|
|
188
|
+
try:
|
|
189
|
+
hits = nodeparam.replace_text(node, args.find, args.replace, property_key=args.property)
|
|
190
|
+
except ValueError as e:
|
|
191
|
+
raise UsageError(str(e)) from e
|
|
192
|
+
|
|
193
|
+
total = sum(h["count"] for h in hits)
|
|
194
|
+
result = {"id": args.id, "title": flow.get("title"), "node": node.get("actionName"),
|
|
195
|
+
"find": args.find, "replace": args.replace,
|
|
196
|
+
"replacements": total, "leaves_changed": len(hits), "hits": hits}
|
|
197
|
+
if args.expect is not None and total != args.expect:
|
|
198
|
+
result["put"] = False
|
|
199
|
+
result["error_note"] = f"expected {args.expect} replacements, found {total} - nothing written"
|
|
200
|
+
return result
|
|
201
|
+
if not hits:
|
|
202
|
+
result["note"] = "literal not found; nothing to PUT"
|
|
203
|
+
result["put"] = False
|
|
204
|
+
return result
|
|
205
|
+
|
|
206
|
+
result["normalized"] = normalize_designer_layer(flow)
|
|
207
|
+
return _gate_and_put(client, flow, args, result)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def variable_set_type(client, args) -> dict:
|
|
211
|
+
flow = _fetch_flow(client, args.id)
|
|
212
|
+
var = nodeparam.find_variable(flow, args.variable)
|
|
213
|
+
if not var:
|
|
214
|
+
raise UsageError(f"variable not found in process {args.id}: {args.variable}")
|
|
215
|
+
is_list = None
|
|
216
|
+
if args.is_list is not None:
|
|
217
|
+
is_list = args.is_list.strip().lower() in ("1", "true", "yes")
|
|
218
|
+
try:
|
|
219
|
+
change = nodeparam.set_variable_type(flow, var, args.data_type, is_list=is_list,
|
|
220
|
+
allow_contract_change=args.allow_contract_change)
|
|
221
|
+
except ValueError as e:
|
|
222
|
+
raise UsageError(str(e)) from e
|
|
223
|
+
|
|
224
|
+
result = {"id": args.id, "title": flow.get("title"), "variable": var.get("name"), **change}
|
|
225
|
+
if not change["changed"]:
|
|
226
|
+
result["note"] = "type already set; nothing to PUT"
|
|
227
|
+
result["put"] = False
|
|
228
|
+
return result
|
|
229
|
+
|
|
230
|
+
return _gate_and_put(client, flow, args, result, block_on_lint=False)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def variable_set_required(client, args) -> dict:
|
|
234
|
+
flow = _fetch_flow(client, args.id)
|
|
235
|
+
var = nodeparam.find_variable(flow, args.variable)
|
|
236
|
+
if not var:
|
|
237
|
+
raise UsageError(f"variable not found in process {args.id}: {args.variable}")
|
|
238
|
+
want = args.required.strip().lower()
|
|
239
|
+
if want not in ("1", "true", "yes", "0", "false", "no"):
|
|
240
|
+
raise UsageError(f"--required must be true or false, got {args.required!r}")
|
|
241
|
+
try:
|
|
242
|
+
change = nodeparam.set_variable_required(
|
|
243
|
+
flow, var, want in ("1", "true", "yes"),
|
|
244
|
+
allow_contract_change=args.allow_contract_change)
|
|
245
|
+
except ValueError as e:
|
|
246
|
+
raise UsageError(str(e)) from e
|
|
247
|
+
|
|
248
|
+
result = {"id": args.id, "title": flow.get("title"), "variable": var.get("name"), **change}
|
|
249
|
+
if not change["changed"]:
|
|
250
|
+
result["note"] = "isRequired already set; nothing to PUT"
|
|
251
|
+
result["put"] = False
|
|
252
|
+
return result
|
|
253
|
+
|
|
254
|
+
valid, errors = _validate(client, flow)
|
|
255
|
+
result["isValid"] = valid
|
|
256
|
+
result["lint_problems"] = _lint(client, flow)
|
|
257
|
+
if not valid: # never PUT an invalid flow
|
|
258
|
+
result["errors"] = errors
|
|
259
|
+
result["put"] = False
|
|
260
|
+
return result
|
|
261
|
+
if args.dry_run:
|
|
262
|
+
result["put"] = False
|
|
263
|
+
result["dry_run"] = True
|
|
264
|
+
return result
|
|
265
|
+
# Every save decides the mark: the platform stores what the body carries,
|
|
266
|
+
# never computes it, so a pass-through PUT files a repaired flow as broken.
|
|
267
|
+
fe = run_fe_validation(client, flow)
|
|
268
|
+
result["fe"] = fe
|
|
269
|
+
saved = save_flow(client, flow, flow_id=args.id, valid=bool(valid and fe["clean"]))
|
|
270
|
+
result["isValid"] = saved["isValid"]
|
|
271
|
+
result["stamped"] = saved["stamped"]
|
|
272
|
+
if "readback_error" in saved:
|
|
273
|
+
result["readback_error"] = saved["readback_error"]
|
|
274
|
+
result["put"] = True
|
|
275
|
+
return result
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def variable_add(client, args) -> dict:
|
|
279
|
+
flow = _fetch_flow(client, args.id)
|
|
280
|
+
try:
|
|
281
|
+
var = nodeparam.add_variable(
|
|
282
|
+
flow, args.name, args.data_type, args.direction,
|
|
283
|
+
is_list=bool(args.is_list), default_value=args.default,
|
|
284
|
+
is_required=bool(args.required))
|
|
285
|
+
except ValueError as e:
|
|
286
|
+
raise UsageError(str(e)) from e
|
|
287
|
+
|
|
288
|
+
result = {"id": args.id, "title": flow.get("title"), "variable": var["name"],
|
|
289
|
+
"variable_id": var["id"], "dataType": var["dataType"],
|
|
290
|
+
"direction": args.direction.lower(), "isList": var["isList"],
|
|
291
|
+
"isRequired": var["isRequired"]}
|
|
292
|
+
|
|
293
|
+
valid, errors = _validate(client, flow)
|
|
294
|
+
result["isValid"] = valid
|
|
295
|
+
result["lint_problems"] = _lint(client, flow)
|
|
296
|
+
if not valid: # never PUT an invalid flow
|
|
297
|
+
result["errors"] = errors
|
|
298
|
+
result["put"] = False
|
|
299
|
+
return result
|
|
300
|
+
if args.dry_run:
|
|
301
|
+
result["put"] = False
|
|
302
|
+
result["dry_run"] = True
|
|
303
|
+
return result
|
|
304
|
+
# Every save decides the mark: the platform stores what the body carries,
|
|
305
|
+
# never computes it, so a pass-through PUT files a repaired flow as broken.
|
|
306
|
+
fe = run_fe_validation(client, flow)
|
|
307
|
+
result["fe"] = fe
|
|
308
|
+
saved = save_flow(client, flow, flow_id=args.id, valid=bool(valid and fe["clean"]))
|
|
309
|
+
result["isValid"] = saved["isValid"]
|
|
310
|
+
result["stamped"] = saved["stamped"]
|
|
311
|
+
if "readback_error" in saved:
|
|
312
|
+
result["readback_error"] = saved["readback_error"]
|
|
313
|
+
result["put"] = True
|
|
314
|
+
return result
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def variable_set_default(client, args) -> dict:
|
|
318
|
+
import io as _io, json as _json
|
|
319
|
+
flow = _fetch_flow(client, args.id)
|
|
320
|
+
var = nodeparam.find_variable(flow, args.variable)
|
|
321
|
+
if not var:
|
|
322
|
+
raise UsageError(f"variable not found in process {args.id}: {args.variable}")
|
|
323
|
+
if args.value is not None and args.value_file:
|
|
324
|
+
raise UsageError("pass either --value or --value-file, not both")
|
|
325
|
+
if args.clear:
|
|
326
|
+
# Clearing needs no value, and combining the two hides which one won.
|
|
327
|
+
if args.value is not None or args.value_file:
|
|
328
|
+
raise UsageError("--clear removes the default; do not combine it with "
|
|
329
|
+
"--value or --value-file")
|
|
330
|
+
value = None
|
|
331
|
+
else:
|
|
332
|
+
if args.value_file:
|
|
333
|
+
raw = _io.open(args.value_file, encoding="utf-8", newline="").read()
|
|
334
|
+
elif args.value is not None:
|
|
335
|
+
raw = args.value
|
|
336
|
+
else:
|
|
337
|
+
raise UsageError("nothing to set: pass --value, --value-file, or --clear")
|
|
338
|
+
if args.json:
|
|
339
|
+
try:
|
|
340
|
+
value = _json.loads(raw)
|
|
341
|
+
except ValueError as e:
|
|
342
|
+
raise UsageError(f"--json was passed but the value is not valid JSON: {e}") from e
|
|
343
|
+
else:
|
|
344
|
+
value = raw
|
|
345
|
+
|
|
346
|
+
try:
|
|
347
|
+
change = nodeparam.set_variable_default(
|
|
348
|
+
flow, var, value, allow_contract_change=args.allow_contract_change)
|
|
349
|
+
except ValueError as e:
|
|
350
|
+
raise UsageError(str(e)) from e
|
|
351
|
+
|
|
352
|
+
result = {"id": args.id, "title": flow.get("title"), "variable": var.get("name"), **change}
|
|
353
|
+
if not change["changed"]:
|
|
354
|
+
result["note"] = "default already set to that value; nothing to PUT"
|
|
355
|
+
result["put"] = False
|
|
356
|
+
return result
|
|
357
|
+
valid, errors = _validate(client, flow)
|
|
358
|
+
result["isValid"] = valid
|
|
359
|
+
result["lint_problems"] = _lint(client, flow)
|
|
360
|
+
if not valid:
|
|
361
|
+
result["errors"] = errors
|
|
362
|
+
result["put"] = False
|
|
363
|
+
return result
|
|
364
|
+
if args.dry_run:
|
|
365
|
+
result["put"] = False
|
|
366
|
+
result["dry_run"] = True
|
|
367
|
+
return result
|
|
368
|
+
# Every save decides the mark: the platform stores what the body carries,
|
|
369
|
+
# never computes it, so a pass-through PUT files a repaired flow as broken.
|
|
370
|
+
fe = run_fe_validation(client, flow)
|
|
371
|
+
result["fe"] = fe
|
|
372
|
+
saved = save_flow(client, flow, flow_id=args.id, valid=bool(valid and fe["clean"]))
|
|
373
|
+
result["isValid"] = saved["isValid"]
|
|
374
|
+
result["stamped"] = saved["stamped"]
|
|
375
|
+
if "readback_error" in saved:
|
|
376
|
+
result["readback_error"] = saved["readback_error"]
|
|
377
|
+
result["put"] = True
|
|
378
|
+
return result
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def node_insert(client, args) -> dict:
|
|
382
|
+
import io as _io, json as _json, uuid as _uuid
|
|
383
|
+
from tools.procesio.dto.process import builder as _b
|
|
384
|
+
|
|
385
|
+
flow = _fetch_flow(client, args.id)
|
|
386
|
+
anchor = nodeparam.find_node(flow, args.after) if hasattr(nodeparam, "find_node") else None
|
|
387
|
+
if anchor is None:
|
|
388
|
+
key = str(args.after).strip().lower()
|
|
389
|
+
for a in flow.get("actions") or []:
|
|
390
|
+
if str(a.get("id")) == args.after or str(a.get("actionName") or "").strip().lower() == key:
|
|
391
|
+
anchor = a
|
|
392
|
+
break
|
|
393
|
+
if anchor is None:
|
|
394
|
+
raise UsageError(f"anchor node not found in process {args.id}: {args.after}")
|
|
395
|
+
|
|
396
|
+
params = {}
|
|
397
|
+
if args.params_file:
|
|
398
|
+
params = _json.loads(_io.open(args.params_file, encoding="utf-8").read())
|
|
399
|
+
elif args.params:
|
|
400
|
+
params = _json.loads(args.params)
|
|
401
|
+
|
|
402
|
+
# ctx the builder needs: the action catalog, this flow's id, and its variables BY NAME so a
|
|
403
|
+
# {"var": "x"} binding resolves to the same guid the rest of the flow already uses.
|
|
404
|
+
ctx = {
|
|
405
|
+
"flow_id": flow.get("id"),
|
|
406
|
+
"catalog": _b.catalog_index(),
|
|
407
|
+
"var_ids": {str(v.get("name")).strip().lower(): v.get("id")
|
|
408
|
+
for v in (flow.get("variables") or [])},
|
|
409
|
+
"var_models": {}, "model_attrs": {},
|
|
410
|
+
"new_id": lambda: str(_uuid.uuid4()),
|
|
411
|
+
}
|
|
412
|
+
try:
|
|
413
|
+
template = _b._resolve_template(args.action, ctx)
|
|
414
|
+
except Exception as e:
|
|
415
|
+
raise UsageError(f"could not resolve action template {args.action!r}: {e}") from e
|
|
416
|
+
|
|
417
|
+
counter = [0]
|
|
418
|
+
built = _b._action_parameters(template, params, ctx, counter)
|
|
419
|
+
pos = ((anchor.get("customData") or {}).get("position") or {})
|
|
420
|
+
dto = _b._action_node(str(_uuid.uuid4()), template, args.name or args.action, built,
|
|
421
|
+
float(pos.get("x") or 0) + 160, float(pos.get("y") or 0), ctx)
|
|
422
|
+
action = nodeparam.to_live_action(dto)
|
|
423
|
+
|
|
424
|
+
ok, message = nodeparam.insert_node(flow, anchor, action)
|
|
425
|
+
result = {"id": args.id, "title": flow.get("title"), "after": anchor.get("actionName"),
|
|
426
|
+
"action": template.get("name"), "node_id": action.get("id"), "message": message}
|
|
427
|
+
if not ok:
|
|
428
|
+
result["inserted"] = False
|
|
429
|
+
result["put"] = False
|
|
430
|
+
return result
|
|
431
|
+
|
|
432
|
+
valid, errors = _validate(client, flow)
|
|
433
|
+
result["isValid"] = valid
|
|
434
|
+
result["lint_problems"] = _lint(client, flow)
|
|
435
|
+
if not valid: # never PUT an invalid flow
|
|
436
|
+
result["errors"] = errors
|
|
437
|
+
result["inserted"] = False
|
|
438
|
+
result["put"] = False
|
|
439
|
+
return result
|
|
440
|
+
if args.dry_run:
|
|
441
|
+
result["inserted"] = True
|
|
442
|
+
result["put"] = False
|
|
443
|
+
result["dry_run"] = True
|
|
444
|
+
return result
|
|
445
|
+
# Every save decides the mark: the platform stores what the body carries,
|
|
446
|
+
# never computes it, so a pass-through PUT files a repaired flow as broken.
|
|
447
|
+
fe = run_fe_validation(client, flow)
|
|
448
|
+
result["fe"] = fe
|
|
449
|
+
saved = save_flow(client, flow, flow_id=args.id, valid=bool(valid and fe["clean"]))
|
|
450
|
+
result["isValid"] = saved["isValid"]
|
|
451
|
+
result["stamped"] = saved["stamped"]
|
|
452
|
+
if "readback_error" in saved:
|
|
453
|
+
result["readback_error"] = saved["readback_error"]
|
|
454
|
+
result["inserted"] = True
|
|
455
|
+
result["put"] = True
|
|
456
|
+
return result
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def process_rename(client, args) -> dict:
|
|
460
|
+
flow = _fetch_flow(client, args.id)
|
|
461
|
+
change = nodeparam.set_process_title(flow, args.title)
|
|
462
|
+
result = {"id": args.id, **change}
|
|
463
|
+
if not change["changed"]:
|
|
464
|
+
result["note"] = "title already set; nothing to PUT"
|
|
465
|
+
result["put"] = False
|
|
466
|
+
return result
|
|
467
|
+
return _gate_and_put(client, flow, args, result, block_on_lint=False)
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
def node_bind_var(client, args) -> dict:
|
|
471
|
+
flow = _fetch_flow(client, args.id)
|
|
472
|
+
node = nodeparam.find_node(flow, args.node)
|
|
473
|
+
if not node:
|
|
474
|
+
raise UsageError(f"node not found in process {args.id}: {args.node}")
|
|
475
|
+
param = nodeparam.find_param(node, args.property)
|
|
476
|
+
if param is None:
|
|
477
|
+
raise UsageError(
|
|
478
|
+
f"property not found on node '{args.node}': {args.property} "
|
|
479
|
+
f"(run node-params --node '{args.node}' to list the labels)")
|
|
480
|
+
bindings = {}
|
|
481
|
+
for spec in args.bind or []:
|
|
482
|
+
if "=" not in spec:
|
|
483
|
+
raise UsageError(f"--bind must be 'INDEX=variable', got: {spec}")
|
|
484
|
+
idx, name = spec.split("=", 1)
|
|
485
|
+
try:
|
|
486
|
+
idx = int(idx.strip())
|
|
487
|
+
except ValueError:
|
|
488
|
+
raise UsageError(f"--bind index must be an integer, got: {idx}")
|
|
489
|
+
var = nodeparam.find_variable(flow, name.strip())
|
|
490
|
+
if not var:
|
|
491
|
+
raise UsageError(f"--bind variable not found in process {args.id}: {name.strip()}")
|
|
492
|
+
bindings[idx] = var.get("id")
|
|
493
|
+
if not bindings:
|
|
494
|
+
raise UsageError("at least one --bind INDEX=variable is required")
|
|
495
|
+
try:
|
|
496
|
+
change = nodeparam.bind_param_var(node, param, bindings, find=args.find, replace=args.replace)
|
|
497
|
+
except ValueError as e:
|
|
498
|
+
raise UsageError(str(e)) from e
|
|
499
|
+
result = {"id": args.id, "title": flow.get("title"), "node": node.get("actionName"),
|
|
500
|
+
"property": param.get("tabPropertyId"), **change}
|
|
501
|
+
result["normalized"] = normalize_designer_layer(flow)
|
|
502
|
+
return _gate_and_put(client, flow, args, result)
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
def _params_args(p: argparse.ArgumentParser) -> None:
|
|
506
|
+
add_profile_arg(p)
|
|
507
|
+
p.add_argument("--id", required=True, help="process (project) id")
|
|
508
|
+
p.add_argument("--node", help="one node's actionName (canvas label) or id; omit for every node")
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
def _set_args(p: argparse.ArgumentParser) -> None:
|
|
512
|
+
add_profile_arg(p)
|
|
513
|
+
p.add_argument("--id", required=True, help="process (project) id")
|
|
514
|
+
p.add_argument("--node", required=True, help="node actionName (canvas label) or id")
|
|
515
|
+
p.add_argument("--property", required=True,
|
|
516
|
+
help="parameter's designer label (e.g. 'Endpoint') or its tabPropertyId")
|
|
517
|
+
p.add_argument("--value",
|
|
518
|
+
help="new literal text; keep every positional variable placeholder the old value had")
|
|
519
|
+
p.add_argument("--value-file", dest="value_file",
|
|
520
|
+
help="read the new literal from a FILE instead of --value. Required for anything "
|
|
521
|
+
"larger than the OS argv limit (~32 KB on Windows) - a big Node body or an "
|
|
522
|
+
"embedded reference table cannot be passed on a command line")
|
|
523
|
+
p.add_argument("--allow-binding-change", dest="allow_binding_change", action="store_true",
|
|
524
|
+
help="permit a different placeholder set (only when variable[] is rewritten too)")
|
|
525
|
+
p.add_argument("--dry-run", dest="dry_run", action="store_true",
|
|
526
|
+
help="patch + normalize + validate but do not PUT")
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
def _delete_args(p: argparse.ArgumentParser) -> None:
|
|
530
|
+
add_profile_arg(p)
|
|
531
|
+
p.add_argument("--id", required=True, help="process (project) id")
|
|
532
|
+
p.add_argument("--node", required=True, help="node actionName (canvas label) or id to delete")
|
|
533
|
+
p.add_argument("--dry-run", dest="dry_run", action="store_true",
|
|
534
|
+
help="delete + heal + validate but do not PUT")
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
def _replace_args(p: argparse.ArgumentParser) -> None:
|
|
538
|
+
add_profile_arg(p)
|
|
539
|
+
p.add_argument("--id", required=True, help="process (project) id")
|
|
540
|
+
p.add_argument("--node", required=True, help="node actionName (canvas label) or id")
|
|
541
|
+
p.add_argument("--property", help="narrow the sweep to one parameter (designer label or tabPropertyId)")
|
|
542
|
+
p.add_argument("--find", required=True, help="exact literal to replace (no regex)")
|
|
543
|
+
p.add_argument("--replace", required=True, help="replacement literal")
|
|
544
|
+
p.add_argument("--expect", type=int,
|
|
545
|
+
help="assert this many replacements; a mismatch writes nothing")
|
|
546
|
+
p.add_argument("--allow-binding-change", dest="allow_binding_change", action="store_true",
|
|
547
|
+
help="permit a find/replace that touches a positional variable placeholder")
|
|
548
|
+
p.add_argument("--dry-run", dest="dry_run", action="store_true",
|
|
549
|
+
help="replace + normalize + validate but do not PUT")
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
def _vartype_args(p: argparse.ArgumentParser) -> None:
|
|
553
|
+
add_profile_arg(p)
|
|
554
|
+
p.add_argument("--id", required=True, help="process (project) id")
|
|
555
|
+
p.add_argument("--variable", required=True, help="variable name or id")
|
|
556
|
+
p.add_argument("--data-type", dest="data_type", required=True,
|
|
557
|
+
help="target dataType id (e.g. ...121221 Object, ...121220 Json, ...121214 String)")
|
|
558
|
+
p.add_argument("--is-list", dest="is_list", help="true/false to also set isList; omit to keep it")
|
|
559
|
+
p.add_argument("--allow-contract-change", dest="allow_contract_change", action="store_true",
|
|
560
|
+
help="permit retyping an input (10) / output (30) variable - changes the public contract")
|
|
561
|
+
p.add_argument("--dry-run", dest="dry_run", action="store_true",
|
|
562
|
+
help="retype + validate but do not PUT")
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
def _varrequired_args(p: argparse.ArgumentParser) -> None:
|
|
566
|
+
add_profile_arg(p)
|
|
567
|
+
p.add_argument("--id", required=True, help="process (project) id")
|
|
568
|
+
p.add_argument("--variable", required=True, help="input variable name or id")
|
|
569
|
+
p.add_argument("--required", required=True,
|
|
570
|
+
help="true to make the input mandatory, false to make it optional")
|
|
571
|
+
p.add_argument("--allow-contract-change", dest="allow_contract_change", action="store_true",
|
|
572
|
+
help="permit making an optional input required - tightens the public contract "
|
|
573
|
+
"and breaks callers that omit it")
|
|
574
|
+
p.add_argument("--dry-run", dest="dry_run", action="store_true",
|
|
575
|
+
help="set + validate but do not PUT")
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
def _varadd_args(p: argparse.ArgumentParser) -> None:
|
|
579
|
+
add_profile_arg(p)
|
|
580
|
+
p.add_argument("--id", required=True, help="process (project) id")
|
|
581
|
+
p.add_argument("--name", required=True, help="new variable name (must be unique in the flow)")
|
|
582
|
+
p.add_argument("--data-type", dest="data_type", required=True,
|
|
583
|
+
help="alias (string, integer, boolean, json, object, file, date, datetime, guid) "
|
|
584
|
+
"or a data-type GUID")
|
|
585
|
+
p.add_argument("--direction", required=True,
|
|
586
|
+
help="input (run payload), process (internal) or output (response)")
|
|
587
|
+
p.add_argument("--is-list", dest="is_list", action="store_true", help="make it a list")
|
|
588
|
+
p.add_argument("--default", help="default value")
|
|
589
|
+
p.add_argument("--required", action="store_true",
|
|
590
|
+
help="mark an input as required (see variable-set-required)")
|
|
591
|
+
p.add_argument("--dry-run", dest="dry_run", action="store_true",
|
|
592
|
+
help="add + validate but do not PUT")
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
def _vardefault_args(p: argparse.ArgumentParser) -> None:
|
|
596
|
+
add_profile_arg(p)
|
|
597
|
+
p.add_argument("--id", required=True, help="process (project) id")
|
|
598
|
+
p.add_argument("--variable", required=True, help="variable name or id")
|
|
599
|
+
p.add_argument("--value", help="the default value, as text")
|
|
600
|
+
p.add_argument("--value-file", dest="value_file",
|
|
601
|
+
help="read the default from a FILE (needed above the ~32 KB argv limit)")
|
|
602
|
+
p.add_argument("--json", action="store_true",
|
|
603
|
+
help="parse the value as JSON before storing it (use for a File object)")
|
|
604
|
+
p.add_argument("--clear", action="store_true", help="clear the default back to null")
|
|
605
|
+
p.add_argument("--allow-contract-change", dest="allow_contract_change", action="store_true",
|
|
606
|
+
help="required for an input/output variable: it changes what a run does when "
|
|
607
|
+
"the caller supplies nothing")
|
|
608
|
+
p.add_argument("--dry-run", dest="dry_run", action="store_true",
|
|
609
|
+
help="set + validate but do not PUT")
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
def _insert_args(p: argparse.ArgumentParser) -> None:
|
|
613
|
+
add_profile_arg(p)
|
|
614
|
+
p.add_argument("--id", required=True, help="process (project) id")
|
|
615
|
+
p.add_argument("--after", required=True,
|
|
616
|
+
help="node to insert AFTER - its actionName (canvas label) or id")
|
|
617
|
+
p.add_argument("--action", required=True,
|
|
618
|
+
help="action template NAME from the catalog (e.g. 'Data Store', 'Decisional')")
|
|
619
|
+
p.add_argument("--name", help="canvas label for the new node (defaults to the template name)")
|
|
620
|
+
p.add_argument("--params", help="parameters as a JSON object of {property label: binding}")
|
|
621
|
+
p.add_argument("--params-file", dest="params_file",
|
|
622
|
+
help="read the parameters JSON from a file (needed above the argv limit)")
|
|
623
|
+
p.add_argument("--dry-run", dest="dry_run", action="store_true",
|
|
624
|
+
help="build + splice + validate but do not PUT")
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
def _prename_args(p: argparse.ArgumentParser) -> None:
|
|
628
|
+
add_profile_arg(p)
|
|
629
|
+
p.add_argument("--id", required=True, help="process (project) id")
|
|
630
|
+
p.add_argument("--title", required=True, help="new process title")
|
|
631
|
+
p.add_argument("--dry-run", dest="dry_run", action="store_true",
|
|
632
|
+
help="patch + validate but do not PUT")
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
def _bindvar_args(p: argparse.ArgumentParser) -> None:
|
|
636
|
+
add_profile_arg(p)
|
|
637
|
+
p.add_argument("--id", required=True, help="process (project) id")
|
|
638
|
+
p.add_argument("--node", required=True, help="node actionName (canvas label) or id")
|
|
639
|
+
p.add_argument("--property", required=True,
|
|
640
|
+
help="parameter's designer label (e.g. 'Body') or its tabPropertyId")
|
|
641
|
+
p.add_argument("--bind", action="append", required=True,
|
|
642
|
+
help="INDEX=variable: bind the value's <%%N%%> placeholder N to a process variable "
|
|
643
|
+
"(name or id). Repeatable. The value's placeholder set must equal the bound set.")
|
|
644
|
+
p.add_argument("--find", help="optional exact literal to replace in the value first (e.g. a "
|
|
645
|
+
"mistyped literal '<%%firstName%%>' token)")
|
|
646
|
+
p.add_argument("--replace", help="replacement for --find (e.g. '<%%0%%>'); empty to delete it")
|
|
647
|
+
p.add_argument("--dry-run", dest="dry_run", action="store_true",
|
|
648
|
+
help="patch + normalize + validate but do not PUT")
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
def node_set_error_port(client, args) -> dict:
|
|
652
|
+
"""Wire (or clear) ONE node's error port on a live process.
|
|
653
|
+
|
|
654
|
+
The reason this is its own action rather than a process-edit config: a desired-state rebuild
|
|
655
|
+
re-derives the whole flow, and the thing being fixed here is usually a flow nobody wants
|
|
656
|
+
re-derived - a designer-built one, or one whose canvas positions are keyed on its action names.
|
|
657
|
+
"""
|
|
658
|
+
flow = _fetch_flow(client, args.id)
|
|
659
|
+
node = nodeparam.find_node(flow, args.node)
|
|
660
|
+
if not node:
|
|
661
|
+
raise UsageError(f"node not found in process {args.id}: {args.node}")
|
|
662
|
+
handler = None
|
|
663
|
+
if not args.clear:
|
|
664
|
+
if not args.handler:
|
|
665
|
+
raise UsageError("--handler is required (or pass --clear to remove the error port)")
|
|
666
|
+
handler = nodeparam.find_node(flow, args.handler)
|
|
667
|
+
if not handler:
|
|
668
|
+
raise UsageError(f"handler node not found in process {args.id}: {args.handler}")
|
|
669
|
+
try:
|
|
670
|
+
change = nodeparam.set_error_port(flow, node, handler, clear=bool(args.clear))
|
|
671
|
+
except ValueError as e:
|
|
672
|
+
raise UsageError(str(e)) from e
|
|
673
|
+
result = {"id": args.id, "title": flow.get("title"), **change}
|
|
674
|
+
result["normalized"] = normalize_designer_layer(flow)
|
|
675
|
+
return _gate_and_put(client, flow, args, result)
|
|
676
|
+
def _errorport_args(p: argparse.ArgumentParser) -> None:
|
|
677
|
+
add_profile_arg(p)
|
|
678
|
+
p.add_argument("--id", required=True, help="process (project) id")
|
|
679
|
+
p.add_argument("--node", required=True,
|
|
680
|
+
help="the node whose error port to wire: actionName (canvas label) or id")
|
|
681
|
+
p.add_argument("--handler",
|
|
682
|
+
help="the action a fault routes to: actionName or id. Its own successor is the "
|
|
683
|
+
"usual choice when that successor already tolerates a missing input")
|
|
684
|
+
p.add_argument("--clear", action="store_true",
|
|
685
|
+
help="remove the error port (and its error variable, if nothing else uses it)")
|
|
686
|
+
p.add_argument("--dry-run", action="store_true",
|
|
687
|
+
help="wire + normalize + validate but do not PUT")
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
def _query_param_source(name: str, spec, kept: dict, flow: dict, tmp: list) -> dict:
|
|
691
|
+
"""One Parameters-map source, from a friendly spec.
|
|
692
|
+
|
|
693
|
+
`keep` is the important one: a live source often carries a resolved ATTRIBUTE path into a
|
|
694
|
+
loop item's model, and re-deriving that from a name would mean re-resolving a model this
|
|
695
|
+
editor never saw. Keeping it verbatim is both safer and shorter.
|
|
696
|
+
"""
|
|
697
|
+
import copy
|
|
698
|
+
|
|
699
|
+
if isinstance(spec, dict) and spec.get("keep"):
|
|
700
|
+
if name not in kept:
|
|
701
|
+
raise UsageError(
|
|
702
|
+
f"--params asks to keep @{name}, but this node's map has no such parameter "
|
|
703
|
+
f"(it has: {', '.join(sorted(k for k in kept if k)) or 'none'})")
|
|
704
|
+
return copy.deepcopy(kept[name])
|
|
705
|
+
if isinstance(spec, dict) and "raw" in spec:
|
|
706
|
+
return copy.deepcopy(spec["raw"])
|
|
707
|
+
if isinstance(spec, dict) and "var" in spec:
|
|
708
|
+
var = nodeparam.find_variable(flow, str(spec["var"]))
|
|
709
|
+
if not var:
|
|
710
|
+
raise UsageError(f"--params @{name} references unknown variable {spec['var']!r}")
|
|
711
|
+
idx = tmp[0]
|
|
712
|
+
tmp[0] += 1
|
|
713
|
+
return {"value": f"<%{idx}%>",
|
|
714
|
+
"variable": [{"id": idx, "variableId": var.get("id"), "attribute": None}]}
|
|
715
|
+
value = spec.get("value") if isinstance(spec, dict) else spec
|
|
716
|
+
return {"value": value, "variable": []}
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
def node_set_query(client, args) -> dict:
|
|
720
|
+
"""Replace a Query Store node's STATEMENT and its chips together, on a live process.
|
|
721
|
+
|
|
722
|
+
node-set-param can only rewrite the text, and it guards that the `<%N%>` set does not move -
|
|
723
|
+
correctly, because those indices bind Variable[] positionally. That makes it useless for the
|
|
724
|
+
edits a statement actually needs: naming one more column, or naming the same column again
|
|
725
|
+
(unavoidable when a value has to be reassembled from several expressions over it, and a
|
|
726
|
+
placeholder cannot be repeated). Here the statement is written with the same
|
|
727
|
+
{{ds:Store}} / {{col:Store.Column}} tokens a config uses, and the chips are regenerated from
|
|
728
|
+
it - so text and bindings cannot drift apart.
|
|
729
|
+
"""
|
|
730
|
+
sql = args.sql
|
|
731
|
+
if args.sql_file:
|
|
732
|
+
with open(args.sql_file, encoding="utf-8") as fh:
|
|
733
|
+
sql = fh.read()
|
|
734
|
+
if not sql or not sql.strip():
|
|
735
|
+
raise UsageError("--sql or --sql-file is required")
|
|
736
|
+
|
|
737
|
+
flow = _fetch_flow(client, args.id)
|
|
738
|
+
node = nodeparam.find_node(flow, args.node)
|
|
739
|
+
if not node:
|
|
740
|
+
raise UsageError(f"node not found in process {args.id}: {args.node}")
|
|
741
|
+
|
|
742
|
+
query, pmap = nodeparam.find_query_params(node)
|
|
743
|
+
if query is None:
|
|
744
|
+
raise UsageError(
|
|
745
|
+
f"node {args.node!r} has no Query Store statement "
|
|
746
|
+
f"(template {node.get('actionTemplateName')!r})")
|
|
747
|
+
spec = None
|
|
748
|
+
if args.params or args.params_file:
|
|
749
|
+
raw = args.params
|
|
750
|
+
if args.params_file:
|
|
751
|
+
with open(args.params_file, encoding="utf-8") as fh:
|
|
752
|
+
raw = fh.read()
|
|
753
|
+
try:
|
|
754
|
+
spec = json.loads(raw)
|
|
755
|
+
except ValueError as e:
|
|
756
|
+
raise UsageError(f"--params must be a JSON object of {{name: source}}: {e}") from e
|
|
757
|
+
if not isinstance(spec, dict):
|
|
758
|
+
raise UsageError("--params must be a JSON OBJECT of {name: source}")
|
|
759
|
+
# The node numbers its query chips, its Parameters-map sources AND its output bindings from
|
|
760
|
+
# ONE sequence. Rewriting the statement alone is safe only while the map is empty; once it is
|
|
761
|
+
# not, the map has to be restated so the whole node can be renumbered together.
|
|
762
|
+
if spec is None and (pmap is not None and (pmap.get("value") or [])):
|
|
763
|
+
raise UsageError(
|
|
764
|
+
"this node's Parameters map is not empty, and its sources share one index sequence "
|
|
765
|
+
"with the statement's chips - restate the map with --params (use {\"keep\": true} "
|
|
766
|
+
"for a source you are not changing) so the node can be renumbered as a whole.")
|
|
767
|
+
|
|
768
|
+
ctx = {"datastore_meta": fetch_datastore_meta(client)}
|
|
769
|
+
before_chips = len(query.get("variable") or [])
|
|
770
|
+
before_text = query.get("value")
|
|
771
|
+
text, chips = render_query_tokens(sql, ctx)
|
|
772
|
+
query["value"] = text
|
|
773
|
+
query["variable"] = chips
|
|
774
|
+
|
|
775
|
+
before_params = [r.get("destination", {}).get("value") for r in (pmap.get("value") or [])] if pmap is not None else []
|
|
776
|
+
if spec is not None:
|
|
777
|
+
if pmap is None:
|
|
778
|
+
raise UsageError("this node has no Parameters map to write")
|
|
779
|
+
kept = {r.get("destination", {}).get("value"): r.get("source")
|
|
780
|
+
for r in (pmap.get("value") or [])}
|
|
781
|
+
# A temporary index clear of everything already in the node: the renumber pass assigns
|
|
782
|
+
# the real ones, and it can only do that if each source starts out distinguishable.
|
|
783
|
+
used = set()
|
|
784
|
+
for p in node.get("parameters") or []:
|
|
785
|
+
used |= nodeparam._collect_indices(p)
|
|
786
|
+
tmp = [max(used) + 1000 if used else 1000]
|
|
787
|
+
rows = []
|
|
788
|
+
for i, (pname, src_spec) in enumerate(spec.items()):
|
|
789
|
+
name = str(pname).lstrip("@")
|
|
790
|
+
rows.append({"id": i, "source": _query_param_source(name, src_spec, kept, flow, tmp),
|
|
791
|
+
"destination": {"value": name, "variable": []}})
|
|
792
|
+
pmap["value"] = rows
|
|
793
|
+
|
|
794
|
+
nodeparam.renumber_node_placeholders(node, [query, pmap])
|
|
795
|
+
|
|
796
|
+
result = {"id": args.id, "title": flow.get("title"), "node": node.get("actionName"),
|
|
797
|
+
"chips_before": before_chips, "chips_after": len(chips),
|
|
798
|
+
"changed": before_text != text,
|
|
799
|
+
"stores_referenced": sorted({c["dataStoreId"] for c in chips if c.get("dataStoreId")}),
|
|
800
|
+
"statement": text}
|
|
801
|
+
result["normalized"] = normalize_designer_layer(flow)
|
|
802
|
+
return _gate_and_put(client, flow, args, result)
|
|
803
|
+
def _setquery_args(p: argparse.ArgumentParser) -> None:
|
|
804
|
+
add_profile_arg(p)
|
|
805
|
+
p.add_argument("--id", required=True, help="process (project) id")
|
|
806
|
+
p.add_argument("--node", required=True,
|
|
807
|
+
help="the Query Store node: actionName (canvas label) or id")
|
|
808
|
+
p.add_argument("--sql", help="the statement, written with {{ds:Store}} / "
|
|
809
|
+
"{{col:Store.Column}} tokens")
|
|
810
|
+
p.add_argument("--sql-file", help="read the statement from a file (needed above the argv "
|
|
811
|
+
"limit, which a real statement usually is)")
|
|
812
|
+
p.add_argument("--params", help="the Parameters map as JSON {name: source}, where a source "
|
|
813
|
+
"is {\"keep\": true} (reuse the live source verbatim, "
|
|
814
|
+
"attribute path included), {\"var\": \"name\"}, "
|
|
815
|
+
"{\"raw\": {...}} or a literal. REQUIRED when the node's "
|
|
816
|
+
"map is non-empty, because the whole node is renumbered")
|
|
817
|
+
p.add_argument("--params-file", help="read the Parameters map JSON from a file")
|
|
818
|
+
p.add_argument("--dry-run", action="store_true",
|
|
819
|
+
help="render + validate but do not PUT")
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
def _resolve_attr(client, flow: dict, varname: str, attrname: str) -> tuple[str, str]:
|
|
823
|
+
"""(variableId, attributeId) for `variable.Attribute`, resolving the attribute BY NAME.
|
|
824
|
+
|
|
825
|
+
By name rather than by id because an id is unreadable in a command line and unverifiable by
|
|
826
|
+
the next reader, while a name is checked here against the variable's own model - so a typo is
|
|
827
|
+
refused with the list of what the model actually has, instead of writing a binding that
|
|
828
|
+
resolves to nothing at run time.
|
|
829
|
+
"""
|
|
830
|
+
var = nodeparam.find_variable(flow, varname)
|
|
831
|
+
if not var:
|
|
832
|
+
raise UsageError(f"--bind references unknown variable {varname!r}")
|
|
833
|
+
model = var.get("dataType")
|
|
834
|
+
if not model:
|
|
835
|
+
raise UsageError(f"variable {varname!r} has no data model, so it has no attributes")
|
|
836
|
+
try:
|
|
837
|
+
dt = client.get(f"/api/DataTypes/{model}") or {}
|
|
838
|
+
except ProcesioAPIError as e:
|
|
839
|
+
raise UsageError(f"could not read the model of {varname!r}: {e}") from e
|
|
840
|
+
attrs = dt.get("attributes") or dt.get("Attributes") or []
|
|
841
|
+
want = attrname.strip().lower()
|
|
842
|
+
for at in attrs:
|
|
843
|
+
if str(at.get("name") or at.get("Name") or "").strip().lower() == want:
|
|
844
|
+
return var["id"], (at.get("id") or at.get("Id"))
|
|
845
|
+
known = ", ".join(sorted(str(a.get("name") or a.get("Name")) for a in attrs)) or "(none)"
|
|
846
|
+
raise UsageError(f"{varname!r} has no attribute {attrname!r}; it has: {known}")
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+
def node_add_binding(client, args) -> dict:
|
|
850
|
+
"""Add bindings to ONE node parameter, with an optional literal edit in the same write.
|
|
851
|
+
|
|
852
|
+
The gap this fills: node-bind-var takes a string parameter and replaces the whole binding
|
|
853
|
+
list, and node-replace-text refuses a replacement containing a `<%N%>`. Neither can do the
|
|
854
|
+
edit that keeps coming up - put one more placeholder inside a STRUCTURED parameter (an HTTP
|
|
855
|
+
body template is a dict) and bind it, without restating the bindings already there.
|
|
856
|
+
"""
|
|
857
|
+
flow = _fetch_flow(client, args.id)
|
|
858
|
+
node = nodeparam.find_node(flow, args.node)
|
|
859
|
+
if not node:
|
|
860
|
+
raise UsageError(f"node not found in process {args.id}: {args.node}")
|
|
861
|
+
param = nodeparam.find_param(node, args.property)
|
|
862
|
+
if param is None:
|
|
863
|
+
raise UsageError(
|
|
864
|
+
f"property not found on node '{args.node}': {args.property} "
|
|
865
|
+
f"(run node-params --node '{args.node}' to list the labels)")
|
|
866
|
+
|
|
867
|
+
bindings = {}
|
|
868
|
+
for spec in args.bind or []:
|
|
869
|
+
if "=" not in spec:
|
|
870
|
+
raise UsageError(f"--bind must be 'INDEX=variable[.Attribute]', got: {spec}")
|
|
871
|
+
idx, ref = spec.split("=", 1)
|
|
872
|
+
try:
|
|
873
|
+
idx = int(idx.strip())
|
|
874
|
+
except ValueError:
|
|
875
|
+
raise UsageError(f"--bind index must be an integer, got: {idx}")
|
|
876
|
+
ref = ref.strip()
|
|
877
|
+
if "." in ref:
|
|
878
|
+
varname, _, attrname = ref.partition(".")
|
|
879
|
+
vid, aid = _resolve_attr(client, flow, varname, attrname)
|
|
880
|
+
bindings[idx] = {"variableId": vid, "attributeId": aid}
|
|
881
|
+
else:
|
|
882
|
+
var = nodeparam.find_variable(flow, ref)
|
|
883
|
+
if not var:
|
|
884
|
+
raise UsageError(f"--bind references unknown variable {ref!r}")
|
|
885
|
+
bindings[idx] = {"variableId": var["id"], "attributeId": None}
|
|
886
|
+
|
|
887
|
+
try:
|
|
888
|
+
change = nodeparam.add_param_bindings(node, param, bindings,
|
|
889
|
+
find=args.find, replace=args.replace)
|
|
890
|
+
except ValueError as e:
|
|
891
|
+
raise UsageError(str(e)) from e
|
|
892
|
+
result = {"id": args.id, "title": flow.get("title"), "node": node.get("actionName"),
|
|
893
|
+
"property": param.get("tabPropertyId"), **change}
|
|
894
|
+
return _gate_and_put(client, flow, args, result)
|
|
895
|
+
def _addbinding_args(p: argparse.ArgumentParser) -> None:
|
|
896
|
+
add_profile_arg(p)
|
|
897
|
+
p.add_argument("--id", required=True, help="process (project) id")
|
|
898
|
+
p.add_argument("--node", required=True, help="node actionName (canvas label) or id")
|
|
899
|
+
p.add_argument("--property", required=True,
|
|
900
|
+
help="the parameter's designer label (e.g. 'Request Parameters') or its id")
|
|
901
|
+
p.add_argument("--bind", action="append",
|
|
902
|
+
help="INDEX=variable or INDEX=variable.Attribute (repeatable). The attribute "
|
|
903
|
+
"is resolved BY NAME against the variable's model, so a typo is refused "
|
|
904
|
+
"rather than written")
|
|
905
|
+
p.add_argument("--find", help="exact literal to replace first (reaches every string leaf, so "
|
|
906
|
+
"it works inside a structured parameter)")
|
|
907
|
+
p.add_argument("--replace", help="replacement literal; unlike node-replace-text it MAY "
|
|
908
|
+
"introduce a new placeholder, which is the point")
|
|
909
|
+
p.add_argument("--dry-run", action="store_true",
|
|
910
|
+
help="edit + validate but do not PUT")
|
|
911
|
+
|
|
912
|
+
|
|
913
|
+
ACTIONS = {
|
|
914
|
+
"node-insert": ActionDef(
|
|
915
|
+
func=node_insert, add_args=_insert_args, needs_client=True,
|
|
916
|
+
description="Insert ONE action into a live process immediately after another, rewiring the "
|
|
917
|
+
"graph: the new node takes the anchor's successor and the anchor is repointed at "
|
|
918
|
+
"it -> validate + flow-lint -> PUT. Refuses an anchor with more than one outgoing "
|
|
919
|
+
"port (which branch it belongs on is a design decision). --dry-run previews."),
|
|
920
|
+
"node-params": ActionDef(
|
|
921
|
+
func=node_params, add_args=_params_args, needs_client=True,
|
|
922
|
+
description="List a live process's nodes with each runtime parameter's designer label, "
|
|
923
|
+
"current value, editability and bound variables (read-only)."),
|
|
924
|
+
"node-set-param": ActionDef(
|
|
925
|
+
func=node_set_param, add_args=_set_args, needs_client=True,
|
|
926
|
+
description="Surgically set ONE node parameter's literal text on a live process (an endpoint, "
|
|
927
|
+
"timeout, SQL or script body) -> regenerate the designer layer from the runtime "
|
|
928
|
+
"layer -> validate + flow-lint -> PUT. --dry-run to preview; an invalid flow is "
|
|
929
|
+
"never PUT. Structured (list/dict) parameters stay process-edit territory."),
|
|
930
|
+
"node-delete": ActionDef(
|
|
931
|
+
func=node_delete, add_args=_delete_args, needs_client=True,
|
|
932
|
+
description="Delete ONE action from a live process and heal the graph: every port that pointed "
|
|
933
|
+
"at it is re-pointed at its successor (or dropped when it has none) -> validate + "
|
|
934
|
+
"flow-lint -> PUT. Refuses Start/Stop and a node with more than one outgoing port. "
|
|
935
|
+
"--dry-run previews; variables are left alone."),
|
|
936
|
+
"node-bind-var": ActionDef(
|
|
937
|
+
func=node_bind_var, add_args=_bindvar_args, needs_client=True,
|
|
938
|
+
description="Bind a process variable into one node parameter's value: set its variable[] "
|
|
939
|
+
"so a <%N%> placeholder actually substitutes at runtime. --bind INDEX=variable "
|
|
940
|
+
"(repeatable); optional --find/--replace turns a mistyped literal token (e.g. a "
|
|
941
|
+
"text '<%firstName%>' that never resolves) into '<%0%>' in the same write. The "
|
|
942
|
+
"value's placeholder set must equal the bound set. Regenerates the designer layer "
|
|
943
|
+
"-> validate + flow-lint -> PUT. --dry-run previews."),
|
|
944
|
+
"node-set-error-port": ActionDef(
|
|
945
|
+
func=node_set_error_port, add_args=_errorport_args, needs_client=True,
|
|
946
|
+
description="Wire ONE node's error port to a handler action on a live process, so a fault "
|
|
947
|
+
"routes instead of killing the run. Writes all THREE parts the engine needs (the "
|
|
948
|
+
"type-1 port, the node's variableErrorId, and an isError variable of the error "
|
|
949
|
+
"datatype); wiring only some of them validates clean and never fires. Reach for it "
|
|
950
|
+
"when a flow a FORM launches on load must still reach Stop with one section empty. "
|
|
951
|
+
"The handler is named, never inferred, because it has to tolerate a null input - "
|
|
952
|
+
"the node's own successor is the usual choice. --clear removes it. Refused on "
|
|
953
|
+
"Start/Stop/Join/For Each, which have no error port. Validates + flow-lints before "
|
|
954
|
+
"PUT; --dry-run previews."),
|
|
955
|
+
"node-set-query": ActionDef(
|
|
956
|
+
func=node_set_query, add_args=_setquery_args, needs_client=True,
|
|
957
|
+
description="Replace a Query Store node's STATEMENT and its Data Store chips together on "
|
|
958
|
+
"a live process, writing the SQL with the same {{ds:Store}} / "
|
|
959
|
+
"{{col:Store.Column}} tokens a process config uses. This is the edit "
|
|
960
|
+
"node-set-param cannot make: it holds the `<%N%>` set fixed (those indices "
|
|
961
|
+
"bind Variable[] positionally), so it refuses a statement that names one more "
|
|
962
|
+
"column - or names the same column twice, which is unavoidable when a value "
|
|
963
|
+
"must be rebuilt from several expressions over it, because a placeholder is "
|
|
964
|
+
"not reusable. Each token occurrence gets its own chip. Refused when the "
|
|
965
|
+
"node's Parameters map is non-empty, since the map's sources share the index "
|
|
966
|
+
"sequence. Validates + flow-lints before PUT; --dry-run previews."),
|
|
967
|
+
"node-add-binding": ActionDef(
|
|
968
|
+
func=node_add_binding, add_args=_addbinding_args, needs_client=True,
|
|
969
|
+
description="Add bindings to ONE node parameter, optionally editing its text in the same "
|
|
970
|
+
"write - the edit neither node-bind-var nor node-replace-text can make. "
|
|
971
|
+
"node-bind-var takes a STRING parameter and replaces the whole binding list; "
|
|
972
|
+
"node-replace-text refuses a replacement that contains a <%N%>. This one "
|
|
973
|
+
"reaches inside a STRUCTURED parameter (an HTTP body template is a dict), may "
|
|
974
|
+
"introduce a new placeholder, and KEEPS the bindings already there. "
|
|
975
|
+
"--bind INDEX=variable.Attribute resolves the attribute by NAME against the "
|
|
976
|
+
"variable's model, so a wrong one is refused with the list of real ones "
|
|
977
|
+
"instead of binding to nothing at run time. Refuses an edit that leaves a "
|
|
978
|
+
"<%N%> unbound or a binding unused. Validates + flow-lints before PUT; "
|
|
979
|
+
"--dry-run previews."),
|
|
980
|
+
"node-replace-text": ActionDef(
|
|
981
|
+
func=node_replace_text, add_args=_replace_args, needs_client=True,
|
|
982
|
+
description="Replace an EXACT literal in every string leaf of a node's runtime parameters AND "
|
|
983
|
+
"designer settings on a live process - the safe way to reach a value nested inside "
|
|
984
|
+
"a structured parameter (a Map Data expression, a decisional literal). --expect N "
|
|
985
|
+
"asserts the hit count; --dry-run previews. Validates + flow-lints before PUT."),
|
|
986
|
+
"variable-set-type": ActionDef(
|
|
987
|
+
func=variable_set_type, add_args=_vartype_args, needs_client=True,
|
|
988
|
+
description="Retype one variable of a live process (dataType, optionally isList) -> validate + "
|
|
989
|
+
"flow-lint -> PUT. Refuses an input/output variable without --allow-contract-change, "
|
|
990
|
+
"because those are the run payload and the response shape callers depend on."),
|
|
991
|
+
"variable-add": ActionDef(
|
|
992
|
+
func=variable_add, add_args=_varadd_args, needs_client=True,
|
|
993
|
+
description="Add ONE variable to a live process (name, data type, direction) -> validate + "
|
|
994
|
+
"flow-lint -> PUT. Safe for existing wiring: everything else addresses variables "
|
|
995
|
+
"by id, and nothing can already point at an id that did not exist. Refuses a "
|
|
996
|
+
"duplicate NAME (the form-event tooling resolves names to ids) and an unknown "
|
|
997
|
+
"direction. --dry-run previews."),
|
|
998
|
+
"variable-set-default": ActionDef(
|
|
999
|
+
func=variable_set_default, add_args=_vardefault_args, needs_client=True,
|
|
1000
|
+
description="Set (or --clear) one variable's defaultValue on a live process -> validate + "
|
|
1001
|
+
"flow-lint -> PUT. This is how an input stops being something the caller must "
|
|
1002
|
+
"supply: a File default is honoured on a run that omits it, and the platform "
|
|
1003
|
+
"re-stages the file into that run's own instance. Needs --allow-contract-change "
|
|
1004
|
+
"on an input/output. --json parses the value first (use for a File object)."),
|
|
1005
|
+
"variable-set-required": ActionDef(
|
|
1006
|
+
func=variable_set_required, add_args=_varrequired_args, needs_client=True,
|
|
1007
|
+
description="Set or clear one INPUT variable's isRequired flag on a live process -> validate "
|
|
1008
|
+
"+ flow-lint -> PUT. Clearing it is allowed outright (no existing caller breaks); "
|
|
1009
|
+
"making an optional input required needs --allow-contract-change. Refused on a "
|
|
1010
|
+
"non-input variable. Guard any bare raw placeholder that reads the variable "
|
|
1011
|
+
"(`var f = <%6%>;` -> `[<%6%>][0]`) BEFORE clearing, or an absent value becomes "
|
|
1012
|
+
"a SyntaxError at run time."),
|
|
1013
|
+
"process-rename": ActionDef(
|
|
1014
|
+
func=process_rename, add_args=_prename_args, needs_client=True,
|
|
1015
|
+
description="Rename a live process (its title) -> validate + flow-lint -> PUT. The title is "
|
|
1016
|
+
"cosmetic (wiring is by id), so this is the safe way to give a '... (Copy)' from "
|
|
1017
|
+
"duplicate-process a real name without a desired-state rebuild. --dry-run previews."),
|
|
1018
|
+
}
|