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,705 @@
|
|
|
1
|
+
"""AAT-facing logic for the MCP bridge — pure, testable, no protocol code.
|
|
2
|
+
|
|
3
|
+
Exposes the live registry to a driver as a small generic surface and executes
|
|
4
|
+
capabilities by shelling to scripts/run-tool.py / run-agent.py with a Python LIST
|
|
5
|
+
argv (no shell), so structured args (including JSON objects) pass cleanly. This is
|
|
6
|
+
the fix for the bash-passthrough tax observed in the B0 spike: the model no longer
|
|
7
|
+
fights shell quote-escaping, and gets typed capability schemas instead of `--help`
|
|
8
|
+
spelunking.
|
|
9
|
+
|
|
10
|
+
Execution reuses dashboard.server.runner (the existing, tested subprocess bridge)
|
|
11
|
+
so there is ONE definition of "run a framework script and normalize its JSON".
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import contextvars
|
|
16
|
+
import difflib
|
|
17
|
+
import json
|
|
18
|
+
import os
|
|
19
|
+
import sys
|
|
20
|
+
import time
|
|
21
|
+
import urllib.error
|
|
22
|
+
import urllib.request
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from typing import Any
|
|
25
|
+
|
|
26
|
+
_REPO = Path(__file__).resolve().parents[2]
|
|
27
|
+
if str(_REPO) not in sys.path:
|
|
28
|
+
sys.path.insert(0, str(_REPO))
|
|
29
|
+
|
|
30
|
+
import registry # noqa: E402
|
|
31
|
+
from tools._lib.skill_resources import read_text_resource, resource_index # noqa: E402
|
|
32
|
+
from dashboard.server import runner # noqa: E402 (shared shell-to-script bridge)
|
|
33
|
+
from tools._lib import accounting # noqa: E402 (per-work-unit accounting seam, P0.0-05)
|
|
34
|
+
|
|
35
|
+
# Per-request user id (multi-user web platform). Set by the aat-mcp HTTP server from a
|
|
36
|
+
# SERVER-ESTABLISHED header (the authenticated session), NEVER from model output. Read
|
|
37
|
+
# here to run the tool/agent subprocess as that user, so userdata + creds isolate
|
|
38
|
+
# per-user (userdata.base() -> <root>/<user>, file creds -> per-user namespace). Unset =
|
|
39
|
+
# single-user, exactly as before (local Claude Code unaffected).
|
|
40
|
+
_user_ctx: "contextvars.ContextVar" = contextvars.ContextVar("aat_user_id", default=None)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def set_user(uid: str | None):
|
|
44
|
+
"""Set the current request's user; returns a token for reset_user()."""
|
|
45
|
+
return _user_ctx.set(uid or None)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def reset_user(token) -> None:
|
|
49
|
+
_user_ctx.reset(token)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# Per-request WORKSPACE id (multi-tenant PROCESIO module, spec P0.0-01). Set alongside
|
|
53
|
+
# the user from the SERVER-ESTABLISHED session, never from model output. Threads
|
|
54
|
+
# AAT_WORKSPACE_ID into the tool/agent subprocess env so userdata + creds isolate per
|
|
55
|
+
# (workspace, user). Unset = single-workspace, exactly as before.
|
|
56
|
+
_workspace_ctx: "contextvars.ContextVar" = contextvars.ContextVar(
|
|
57
|
+
"aat_workspace_id", default=None)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def set_workspace(ws: str | None):
|
|
61
|
+
"""Set the current request's workspace; returns a token for reset_workspace()."""
|
|
62
|
+
return _workspace_ctx.set(ws or None)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def reset_workspace(token) -> None:
|
|
66
|
+
_workspace_ctx.reset(token)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# Managed turn: this request belongs to a turn some OUTER runner already drives (the .NET planner's
|
|
70
|
+
# step loop, a scheduled job, ...). Set from a SERVER-ESTABLISHED header, never from model output.
|
|
71
|
+
#
|
|
72
|
+
# Why a mechanism and not a prompt line: the framework's own `orchestrator drive` is a second, full
|
|
73
|
+
# orchestration loop — it asks a SEPARATE configured llm provider for the next action and executes it,
|
|
74
|
+
# with its own run ledger, step cap and token budget. Started from inside a managed step you get two
|
|
75
|
+
# planners fighting, two run records, and a second model's spend. The step prompt says not to; the MCP
|
|
76
|
+
# tool description for run_agent says to route everything through the orchestrator; the model sees
|
|
77
|
+
# both. This settles it in code for the one action that actually starts a competing loop.
|
|
78
|
+
_managed_ctx: "contextvars.ContextVar" = contextvars.ContextVar("aat_managed_turn", default=False)
|
|
79
|
+
|
|
80
|
+
# "agent:action" pairs refused during a managed turn. Deliberately narrow: `drive` starts the
|
|
81
|
+
# competing loop, while `intake` / `route` / `record` are read-or-bookkeeping and stay allowed, so a
|
|
82
|
+
# managed turn keeps the doctrine available without being able to fork the control flow.
|
|
83
|
+
_DEFAULT_MANAGED_TURN_BLOCK = "orchestrator:drive"
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def set_managed_turn(flag):
|
|
87
|
+
"""Mark this request as part of an externally-driven turn; returns a reset token."""
|
|
88
|
+
return _managed_ctx.set(bool(flag))
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def reset_managed_turn(token) -> None:
|
|
92
|
+
_managed_ctx.reset(token)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _managed_turn_block() -> set[tuple[str, str]]:
|
|
96
|
+
raw = os.environ.get("AAT_MCP_MANAGED_TURN_BLOCK", _DEFAULT_MANAGED_TURN_BLOCK)
|
|
97
|
+
out: set[tuple[str, str]] = set()
|
|
98
|
+
for item in raw.split(","):
|
|
99
|
+
name, _, action = item.strip().partition(":")
|
|
100
|
+
if name and action:
|
|
101
|
+
out.add((name.lower(), action.lower()))
|
|
102
|
+
return out
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _managed_turn_refusal(agent: str, action: str | None) -> dict | None:
|
|
106
|
+
"""The refusal payload when a managed turn reaches for a competing driver, else None."""
|
|
107
|
+
if not _managed_ctx.get():
|
|
108
|
+
return None
|
|
109
|
+
if (agent.lower(), (action or "").lower()) not in _managed_turn_block():
|
|
110
|
+
return None
|
|
111
|
+
return {"ok": False, "refused": {
|
|
112
|
+
"agent": agent, "action": action, "reason": "managed_turn",
|
|
113
|
+
"message": (f"'{agent} {action}' starts a second orchestration loop, and this turn is already "
|
|
114
|
+
f"one step of an externally-managed plan. Do the concrete increment yourself with "
|
|
115
|
+
f"run_tool / run_agent, then end your reply with the control line you were given."),
|
|
116
|
+
}}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _user_env() -> dict | None:
|
|
120
|
+
env: dict = {}
|
|
121
|
+
uid = _user_ctx.get()
|
|
122
|
+
if uid:
|
|
123
|
+
env["AAT_USER_ID"] = str(uid)
|
|
124
|
+
ws = _workspace_ctx.get()
|
|
125
|
+
if ws:
|
|
126
|
+
env["AAT_WORKSPACE_ID"] = str(ws)
|
|
127
|
+
return env or None
|
|
128
|
+
|
|
129
|
+
# Tools that cannot run in a container (browser/profile, DB driver, media system libs).
|
|
130
|
+
# When AAT_HOST_RUNNER_URL is set, these (and agents that drive them) are executed on
|
|
131
|
+
# the HOST via the host-runner instead of in-container. Extend via AAT_HOST_ONLY_TOOLS.
|
|
132
|
+
_HOST_ONLY_TOOLS = {
|
|
133
|
+
"sqlserver", "web",
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _host_only_set() -> set[str]:
|
|
138
|
+
extra = {t.strip() for t in os.environ.get("AAT_HOST_ONLY_TOOLS", "").split(",") if t.strip()}
|
|
139
|
+
return _HOST_ONLY_TOOLS | extra
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _is_host_only(kind: str, name: str) -> bool:
|
|
143
|
+
"""A tool is host-only if listed or its manifest declares a web_session. An agent
|
|
144
|
+
is host-only if any tool it drives is host-only."""
|
|
145
|
+
hoset = _host_only_set()
|
|
146
|
+
if kind == "tool":
|
|
147
|
+
if name in hoset:
|
|
148
|
+
return True
|
|
149
|
+
try:
|
|
150
|
+
return getattr(registry.get_tool(name), "web_session", None) is not None
|
|
151
|
+
except Exception: # noqa: BLE001
|
|
152
|
+
return False
|
|
153
|
+
try:
|
|
154
|
+
drives = set(getattr(registry.get_agent(name), "tools", []) or [])
|
|
155
|
+
except Exception: # noqa: BLE001
|
|
156
|
+
return False
|
|
157
|
+
if drives & hoset:
|
|
158
|
+
return True
|
|
159
|
+
for t in drives:
|
|
160
|
+
try:
|
|
161
|
+
if getattr(registry.get_tool(t), "web_session", None) is not None:
|
|
162
|
+
return True
|
|
163
|
+
except Exception: # noqa: BLE001
|
|
164
|
+
pass
|
|
165
|
+
return False
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _delegate(kind: str, name: str, action: str | None, args: dict | None) -> dict:
|
|
169
|
+
"""Run a host-only tool/agent on the host via the host-runner."""
|
|
170
|
+
url = os.environ["AAT_HOST_RUNNER_URL"].rstrip("/") + "/run"
|
|
171
|
+
token = os.environ.get("AAT_HOST_RUNNER_TOKEN", "")
|
|
172
|
+
payload = json.dumps({"kind": kind, "name": name, "action": action,
|
|
173
|
+
"args": args or {}}).encode("utf-8")
|
|
174
|
+
headers = {"Content-Type": "application/json"}
|
|
175
|
+
if token:
|
|
176
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
177
|
+
uid = _user_ctx.get()
|
|
178
|
+
if uid:
|
|
179
|
+
headers["X-AAT-User"] = str(uid) # host-only tools run as this user too
|
|
180
|
+
ws = _workspace_ctx.get()
|
|
181
|
+
if ws:
|
|
182
|
+
headers["X-AAT-Workspace"] = str(ws) # ...and in this workspace
|
|
183
|
+
req = urllib.request.Request(url, data=payload, method="POST", headers=headers)
|
|
184
|
+
try:
|
|
185
|
+
with urllib.request.urlopen(req, timeout=330) as resp: # noqa: S310 (host-local)
|
|
186
|
+
return json.loads(resp.read().decode("utf-8") or "null")
|
|
187
|
+
except urllib.error.URLError as e:
|
|
188
|
+
return {"ok": False, "error": {"code": "host_runner_unreachable",
|
|
189
|
+
"message": f"host-only {kind} {name!r}: {e}"}}
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _compact(entry: dict, kind: str, full: bool = False) -> dict:
|
|
193
|
+
"""One capability line for the discovery listing. Default is trimmed to keep the
|
|
194
|
+
session context small (a 113-entry listing at 240-char descriptions + examples is
|
|
195
|
+
~50KB that sits in context all session and pushes weaker-window models toward the
|
|
196
|
+
context wall); pass full=True for the fuller line. Either way the complete
|
|
197
|
+
action/arg schema is one `capabilities(name=...)` call away."""
|
|
198
|
+
routing = entry.get("routing") or {}
|
|
199
|
+
desc = entry.get("description") or ""
|
|
200
|
+
out = {
|
|
201
|
+
"kind": kind,
|
|
202
|
+
"name": entry["name"],
|
|
203
|
+
"description": desc[:240] if full else desc[:100],
|
|
204
|
+
"primary_action": routing.get("primary_action", ""),
|
|
205
|
+
"ready": bool(entry.get("ready", True)),
|
|
206
|
+
}
|
|
207
|
+
if full:
|
|
208
|
+
out["example"] = routing.get("example", "")
|
|
209
|
+
return out
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def _args_schema(arglist) -> list[dict]:
|
|
213
|
+
"""One action's (or a flat tool's) argument list, normalized.
|
|
214
|
+
|
|
215
|
+
`name` is the LITERAL flag spelling from the manifest - hyphenated, not
|
|
216
|
+
snake_case. Returning it verbatim is what stops the caller guessing
|
|
217
|
+
`workspace_id` when the flag is `--workspace-id`."""
|
|
218
|
+
out = []
|
|
219
|
+
for arg in (arglist or []):
|
|
220
|
+
spec = {
|
|
221
|
+
"name": arg["name"],
|
|
222
|
+
"type": arg.get("type", "string"),
|
|
223
|
+
"required": bool(arg.get("required", False)),
|
|
224
|
+
"description": arg.get("description", ""),
|
|
225
|
+
}
|
|
226
|
+
# An arg that carries a structured payload publishes its schema. Without it the
|
|
227
|
+
# caller knows the flag and not the contract, and reverse-engineers the shape
|
|
228
|
+
# from validation errors - one layer per attempt, several turns per action.
|
|
229
|
+
if arg.get("schema"):
|
|
230
|
+
spec["schema"] = arg["schema"]
|
|
231
|
+
out.append(spec)
|
|
232
|
+
return out
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _full(entry: dict, kind: str) -> dict:
|
|
236
|
+
"""Full action + arg schema for one capability — the structured replacement for
|
|
237
|
+
`--help`, so the driver never has to spelunk help text."""
|
|
238
|
+
return {
|
|
239
|
+
"kind": kind,
|
|
240
|
+
"name": entry["name"],
|
|
241
|
+
"description": entry.get("description", ""),
|
|
242
|
+
"ready": bool(entry.get("ready", True)),
|
|
243
|
+
"missing_secrets": entry.get("missing_secrets", []),
|
|
244
|
+
"tools": entry.get("tools", []) if kind == "agent" else None,
|
|
245
|
+
# Flat tools (e.g. hello-world) keep args at the top level, not under actions.
|
|
246
|
+
"args": _args_schema(entry.get("args")) if not entry.get("actions") else [],
|
|
247
|
+
"actions": [
|
|
248
|
+
{
|
|
249
|
+
"name": a["name"],
|
|
250
|
+
"description": a.get("description", ""),
|
|
251
|
+
"args": _args_schema(a.get("args")),
|
|
252
|
+
}
|
|
253
|
+
for a in entry.get("actions", [])
|
|
254
|
+
],
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
_REG_CACHE: dict = {}
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def _scan_registry():
|
|
262
|
+
"""Cache the registry scan (parse ~74 manifests + per-secret presence checks) for a
|
|
263
|
+
short TTL. In a running container the registry is static and the model calls
|
|
264
|
+
capabilities several times per loop; without this each call re-parses every manifest
|
|
265
|
+
and re-checks every secret. AAT_REGISTRY_TTL seconds (0 = off)."""
|
|
266
|
+
ttl = float(os.environ.get("AAT_REGISTRY_TTL", "30") or 0)
|
|
267
|
+
if ttl > 0:
|
|
268
|
+
hit = _REG_CACHE.get("data")
|
|
269
|
+
if hit is not None and hit[1] > time.monotonic():
|
|
270
|
+
return hit[0]
|
|
271
|
+
tools = registry.list_tools()
|
|
272
|
+
agents = registry.list_agents({t["name"]: t for t in tools})
|
|
273
|
+
skills = registry.list_skills()
|
|
274
|
+
if ttl > 0:
|
|
275
|
+
_REG_CACHE["data"] = ((tools, agents, skills), time.monotonic() + ttl)
|
|
276
|
+
return tools, agents, skills
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
# --- targeted discovery ---------------------------------------------------
|
|
280
|
+
#
|
|
281
|
+
# Two halves of the same context problem, solved from different ends. `_compact`
|
|
282
|
+
# trims the NO-NAME listing, which sits in context all session. Everything below
|
|
283
|
+
# handles the WITH-NAME lookup: a big tool's full schema is unusable as a payload
|
|
284
|
+
# (procesio alone is ~369 KB / 379 actions), because the driver truncates it to a
|
|
285
|
+
# single-line file that neither `read` (offset/limit sees one line), `grep`
|
|
286
|
+
# (ripgrep refuses a >64 KB record) nor `bash` (gated) can open - so the model
|
|
287
|
+
# burns a turn and gets nothing. The three doors give it what it needs instead:
|
|
288
|
+
# ONE action's schema (~1-2 KB), a keyword SEARCH over actions, and - when it asks
|
|
289
|
+
# for the whole thing anyway - an automatic degrade to the action-name index.
|
|
290
|
+
# The degrade is the point: an instruction in the prompt can be (and was)
|
|
291
|
+
# ignored, code cannot.
|
|
292
|
+
|
|
293
|
+
_DEFAULT_MAX_BYTES = 40_000
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def _max_bytes() -> int:
|
|
297
|
+
"""Size above which a full capability schema degrades to its action index."""
|
|
298
|
+
try:
|
|
299
|
+
return max(0, int(os.environ.get("AAT_CAPABILITIES_MAX_BYTES",
|
|
300
|
+
_DEFAULT_MAX_BYTES)))
|
|
301
|
+
except ValueError:
|
|
302
|
+
return _DEFAULT_MAX_BYTES
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def _find(name: str, kind: str | None = None) -> tuple[dict | None, str | None]:
|
|
306
|
+
"""Resolve one capability by name -> (entry, 'tool'|'agent'). Tools win ties,
|
|
307
|
+
matching the historical lookup order."""
|
|
308
|
+
tools, agents, _ = _scan_registry()
|
|
309
|
+
if kind in (None, "tool"):
|
|
310
|
+
for e in tools:
|
|
311
|
+
if e.get("name") == name:
|
|
312
|
+
return e, "tool"
|
|
313
|
+
if kind in (None, "agent"):
|
|
314
|
+
for e in agents:
|
|
315
|
+
if e.get("name") == name:
|
|
316
|
+
return e, "agent"
|
|
317
|
+
return None, None
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def _action_names(entry: dict) -> list[str]:
|
|
321
|
+
return [a["name"] for a in (entry.get("actions") or [])]
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def _norm_tokens(name: str) -> set[str]:
|
|
325
|
+
"""Action name -> comparable word set, singularized. `credential-list` and
|
|
326
|
+
`list-credentials` must come out equal: word ORDER and PLURALS are what a
|
|
327
|
+
model gets wrong, and plain edit distance scores both as far apart."""
|
|
328
|
+
return {t[:-1] if t.endswith("s") and len(t) > 3 else t
|
|
329
|
+
for t in name.lower().split("-") if t}
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def _suggest(action: str, names: list[str], n: int = 8) -> list[str]:
|
|
333
|
+
"""Closest real action names for one the caller invented."""
|
|
334
|
+
want = _norm_tokens(action)
|
|
335
|
+
scored: list[tuple[float, str]] = []
|
|
336
|
+
for candidate in names:
|
|
337
|
+
have = _norm_tokens(candidate)
|
|
338
|
+
overlap = len(want & have)
|
|
339
|
+
ratio = difflib.SequenceMatcher(None, action.lower(), candidate.lower()).ratio()
|
|
340
|
+
if not overlap and ratio < 0.5:
|
|
341
|
+
continue
|
|
342
|
+
score = ratio + 2.0 * overlap
|
|
343
|
+
if have == want: # same words, different order/plural - almost always it
|
|
344
|
+
score += 10.0
|
|
345
|
+
scored.append((score, candidate))
|
|
346
|
+
scored.sort(key=lambda s: (-s[0], s[1]))
|
|
347
|
+
return [c for _, c in scored[:n]]
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def _one_action(entry: dict, kind: str, action: str) -> dict:
|
|
351
|
+
"""One action's full arg schema, plus the exact call shape to copy."""
|
|
352
|
+
for a in entry.get("actions") or []:
|
|
353
|
+
if a["name"] == action:
|
|
354
|
+
runner_tool = "aat_run_tool" if kind == "tool" else "aat_run_agent"
|
|
355
|
+
key = "tool" if kind == "tool" else "agent"
|
|
356
|
+
action_out = {
|
|
357
|
+
"name": a["name"],
|
|
358
|
+
"description": a.get("description", ""),
|
|
359
|
+
"args": _args_schema(a.get("args")),
|
|
360
|
+
}
|
|
361
|
+
# A worked example is worth more than the schema on its own: it settles the
|
|
362
|
+
# shape AND the conventions the schema cannot express (how a param binds a
|
|
363
|
+
# variable, which names are literal).
|
|
364
|
+
if a.get("examples"):
|
|
365
|
+
action_out["examples"] = a["examples"]
|
|
366
|
+
if a.get("output_schema"):
|
|
367
|
+
action_out["output_schema"] = a["output_schema"]
|
|
368
|
+
return {"capability": {
|
|
369
|
+
"kind": kind,
|
|
370
|
+
"name": entry["name"],
|
|
371
|
+
"action": action_out,
|
|
372
|
+
"call": {runner_tool: {key: entry["name"], "action": a["name"],
|
|
373
|
+
"args": "<flag name -> value>"}},
|
|
374
|
+
"hint": ("Use each arg 'name' EXACTLY as spelled above (hyphens, "
|
|
375
|
+
"not underscores) - it is the literal flag."),
|
|
376
|
+
}}
|
|
377
|
+
names = _action_names(entry)
|
|
378
|
+
return {"unknown_action": action, "of": entry["name"], "kind": kind,
|
|
379
|
+
"action_count": len(names),
|
|
380
|
+
"did_you_mean": _suggest(action, names) or names[:15],
|
|
381
|
+
"hint": (f"{entry['name']} has no action {action!r}. Retry with one of "
|
|
382
|
+
f"did_you_mean, or call capabilities with "
|
|
383
|
+
f"search='<keywords>' to look one up.")}
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def _degraded(entry: dict, kind: str, size: int, limit: int) -> dict:
|
|
387
|
+
"""The over-threshold answer: the action-name INDEX plus how to drill in.
|
|
388
|
+
|
|
389
|
+
Names only (procesio: ~10 KB for 379 of them) instead of the full schema, so
|
|
390
|
+
the caller still sees everything that exists and can then ask for the one
|
|
391
|
+
action it needs."""
|
|
392
|
+
names = _action_names(entry)
|
|
393
|
+
body = {
|
|
394
|
+
"kind": kind,
|
|
395
|
+
"name": entry["name"],
|
|
396
|
+
"description": entry.get("description", ""),
|
|
397
|
+
"ready": bool(entry.get("ready", True)),
|
|
398
|
+
"missing_secrets": entry.get("missing_secrets", []),
|
|
399
|
+
"truncated": True,
|
|
400
|
+
"reason": (f"full schema is {size} bytes, over the {limit}-byte limit; "
|
|
401
|
+
f"returning the action index instead"),
|
|
402
|
+
"action_count": len(names),
|
|
403
|
+
"hint": (f"Call capabilities with name='{entry['name']}' AND "
|
|
404
|
+
f"action='<one of actions>' for that action's arg schema, or "
|
|
405
|
+
f"search='<keywords>' to find the right action by keyword. Do "
|
|
406
|
+
f"NOT try to grep or read the full schema."),
|
|
407
|
+
}
|
|
408
|
+
# Insurance: if even the name index is over budget, drop it and leave search
|
|
409
|
+
# as the only door rather than shipping another unusable payload.
|
|
410
|
+
if len(json.dumps(names, ensure_ascii=False)) <= limit:
|
|
411
|
+
body["actions"] = names
|
|
412
|
+
else:
|
|
413
|
+
body["hint"] = ("Too many actions to list. Call capabilities with "
|
|
414
|
+
f"name='{entry['name']}' and search='<keywords>'.")
|
|
415
|
+
return {"capability": body}
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
_DESTRUCTIVE = {"delete", "remove", "destroy", "drop", "purge", "uninstall"}
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def _search_actions(query: str, kind: str | None = None, name: str | None = None,
|
|
422
|
+
limit: int = 20) -> dict:
|
|
423
|
+
"""Keyword search over ACTIONS (name + description), scoped to one capability
|
|
424
|
+
when `name` is given, otherwise across every tool and agent.
|
|
425
|
+
|
|
426
|
+
AND semantics FIRST: an action matches when every token appears somewhere in
|
|
427
|
+
'<capability>.<action> <description>'. Matches come back COMPACT (no arg schemas) -
|
|
428
|
+
the caller then asks for the one it wants by action name.
|
|
429
|
+
|
|
430
|
+
When AND finds nothing the search RELAXES instead of returning an empty list, and
|
|
431
|
+
says which words it had to drop. A strict-AND miss is not "no such action", it is
|
|
432
|
+
"one of your words is not the word we used", and an empty answer is read as the
|
|
433
|
+
former: observed live, `search "procesio form create template"` returned 0 because
|
|
434
|
+
no description contains "template" - so a run abandoned the curated `form-create`
|
|
435
|
+
(which "procesio create form" finds instantly), fell back to the raw Swagger
|
|
436
|
+
endpoint, tripped the irreversibility gate, and blocked at step 0. The words a
|
|
437
|
+
caller guesses come from the target system's vocabulary, not ours, so one wrong
|
|
438
|
+
guess must not hide the whole family."""
|
|
439
|
+
tokens = [t for t in (query or "").lower().split() if t]
|
|
440
|
+
if not tokens:
|
|
441
|
+
raise KeyError("search requires at least one keyword")
|
|
442
|
+
|
|
443
|
+
tools, agents, _ = _scan_registry()
|
|
444
|
+
pools: list[tuple[list[dict], str]] = []
|
|
445
|
+
if kind in (None, "tool"):
|
|
446
|
+
pools.append((tools, "tool"))
|
|
447
|
+
if kind in (None, "agent"):
|
|
448
|
+
pools.append((agents, "agent"))
|
|
449
|
+
|
|
450
|
+
# A token equal to the capability being searched carries NO information once the
|
|
451
|
+
# search is already scoped to it - every one of that capability's actions contains it.
|
|
452
|
+
# Left in, it lets a query whose real words all miss ("procesio zzzz qqqq") still
|
|
453
|
+
# score 1 everywhere and hand back the entire catalog, which is worse than the empty
|
|
454
|
+
# answer this function is trying to fix. Unscoped it stays: there, naming the tool IS
|
|
455
|
+
# how you narrow.
|
|
456
|
+
informative = [t for t in tokens if not (name and t == name.lower())]
|
|
457
|
+
if not informative:
|
|
458
|
+
informative = tokens
|
|
459
|
+
|
|
460
|
+
# One pass, scoring every action by HOW MANY informative tokens it carries. The strict
|
|
461
|
+
# answer is the full-count group; a relaxation is the next count down, i.e. the largest
|
|
462
|
+
# subset of the query that matches anything - no subset enumeration needed.
|
|
463
|
+
candidates: list[tuple[int, float, int, dict]] = [] # (hits, precision, score, match)
|
|
464
|
+
for pool, pool_kind in pools:
|
|
465
|
+
for entry in pool:
|
|
466
|
+
if entry.get("error"):
|
|
467
|
+
continue
|
|
468
|
+
if name and entry.get("name") != name:
|
|
469
|
+
continue
|
|
470
|
+
for a in entry.get("actions") or []:
|
|
471
|
+
action = a["name"]
|
|
472
|
+
desc = a.get("description", "") or ""
|
|
473
|
+
hay = f"{entry['name']}.{action} {desc}".lower()
|
|
474
|
+
hit = [t for t in informative if t in hay]
|
|
475
|
+
if not hit:
|
|
476
|
+
continue
|
|
477
|
+
low = action.lower()
|
|
478
|
+
score = sum(t in low for t in informative) * 10
|
|
479
|
+
if low == query.strip().lower():
|
|
480
|
+
score += 100
|
|
481
|
+
elif all(t in low for t in informative):
|
|
482
|
+
score += 50
|
|
483
|
+
# How much of the action's NAME the query accounts for. Substring matching
|
|
484
|
+
# makes "template" hit `delete-customurl-formtemplate-by-id` as loudly as
|
|
485
|
+
# it hits `form-create`; counting the name's OWN segments breaks that tie
|
|
486
|
+
# toward the action that is mostly what was asked for, rather than one that
|
|
487
|
+
# merely contains it.
|
|
488
|
+
segs = [s for s in low.replace("_", "-").split("-") if s]
|
|
489
|
+
covered = sum(1 for s in segs if any(t in s or s in t for t in hit))
|
|
490
|
+
precision = covered / len(segs) if segs else 0.0
|
|
491
|
+
# A relaxed search answers a question the caller did not quite ask, so it
|
|
492
|
+
# must not lead with a destructive action: "generate form" and "delete
|
|
493
|
+
# form" match the same one word, and offering the deletion first is how a
|
|
494
|
+
# near-miss becomes an incident. Only demoted when the caller did not ask
|
|
495
|
+
# to destroy anything.
|
|
496
|
+
if _DESTRUCTIVE & set(segs) and not (_DESTRUCTIVE & set(informative)):
|
|
497
|
+
precision -= 1.0
|
|
498
|
+
candidates.append((len(hit), precision, score, {
|
|
499
|
+
"kind": pool_kind,
|
|
500
|
+
"name": entry["name"],
|
|
501
|
+
"action": action,
|
|
502
|
+
"description": desc[:200],
|
|
503
|
+
}))
|
|
504
|
+
|
|
505
|
+
if not candidates:
|
|
506
|
+
return {
|
|
507
|
+
"query": query, "count": 0, "total_matches": 0, "matches": [],
|
|
508
|
+
"hint": ("No action mentions ANY of these words. This is conclusive for AAT's "
|
|
509
|
+
"own catalog - do not rephrase and retry with synonyms. If you are "
|
|
510
|
+
"looking for a building block INSIDE a target system (a node/step "
|
|
511
|
+
"type), it lives in that system, not here: list it with that tool's "
|
|
512
|
+
"own catalog action (for procesio, list-actions-catalog)."),
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
best = max(h for h, _, _, _ in candidates)
|
|
516
|
+
group = [(p, s, m) for h, p, s, m in candidates if h == best]
|
|
517
|
+
group.sort(key=lambda g: (-g[0], -g[1], g[2]["name"], g[2]["action"]))
|
|
518
|
+
matches = [m for _, _, m in group[:limit]]
|
|
519
|
+
|
|
520
|
+
# A relaxation that survived only on a CAPABILITY NAME found nothing: "procesio
|
|
521
|
+
# form-validate" unscoped kept every procesio action alive on the word "procesio"
|
|
522
|
+
# alone and answered with 405 rows, none of them about validating a form. The
|
|
523
|
+
# scoped path strips that token up front; unscoped it cannot, because naming the
|
|
524
|
+
# tool is how you narrow there - so the emptiness has to be recognised here, after
|
|
525
|
+
# scoring. Saying "nothing in procesio mentions form-validate" is both true and
|
|
526
|
+
# what the caller needs; a page of unrelated actions is neither.
|
|
527
|
+
cap_names = {e["name"].lower() for pool, _ in pools for e in pool if e.get("name")}
|
|
528
|
+
surviving = {t for t in informative
|
|
529
|
+
if any(t in f"{m['name']}.{m['action']} {m['description']}".lower()
|
|
530
|
+
for m in matches)}
|
|
531
|
+
if best < len(informative) and surviving and surviving <= cap_names:
|
|
532
|
+
missed = [t for t in informative if t not in surviving]
|
|
533
|
+
where = ", ".join(sorted(surviving))
|
|
534
|
+
return {
|
|
535
|
+
"query": query, "count": 0, "total_matches": 0, "matches": [],
|
|
536
|
+
"relaxed": True, "matched_terms": sorted(surviving), "dropped_terms": missed,
|
|
537
|
+
"hint": (f"Nothing in {where} mentions {missed} - only the capability name "
|
|
538
|
+
f"itself matched, which every one of its actions carries. This is "
|
|
539
|
+
f"conclusive: do not rephrase with synonyms. If {missed} names a "
|
|
540
|
+
f"building block INSIDE the target system (a node/step/control "
|
|
541
|
+
f"type), it lives in that system, not in AAT's catalog - list it "
|
|
542
|
+
f"with that tool's own catalog action (for procesio, "
|
|
543
|
+
f"list-actions-catalog)."),
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
out = {
|
|
547
|
+
"query": query,
|
|
548
|
+
"count": len(matches),
|
|
549
|
+
"total_matches": len(group),
|
|
550
|
+
"matches": matches,
|
|
551
|
+
"hint": ("Call capabilities with name=<name> and action=<action> for that "
|
|
552
|
+
"action's full arg schema before running it."),
|
|
553
|
+
}
|
|
554
|
+
if best < len(informative):
|
|
555
|
+
# Name the dropped words explicitly. A "closest match" that does not say what was
|
|
556
|
+
# ignored invites the caller to trust a result answering a different question.
|
|
557
|
+
# Measured against the TOP match, not the whole page: different matches cover
|
|
558
|
+
# different words, so a set-wide calculation reports "relaxed, dropped nothing",
|
|
559
|
+
# which reads as a contradiction and tells the caller nothing about the action it
|
|
560
|
+
# is actually about to read.
|
|
561
|
+
top = matches[0]
|
|
562
|
+
top_hay = f"{top['name']}.{top['action']} {top['description']}".lower()
|
|
563
|
+
dropped = [t for t in informative if t not in top_hay]
|
|
564
|
+
out["relaxed"] = True
|
|
565
|
+
out["matched_terms"] = [t for t in informative if t not in dropped]
|
|
566
|
+
out["dropped_terms"] = dropped
|
|
567
|
+
out["hint"] = (
|
|
568
|
+
f"No action matches ALL of {informative}; these match "
|
|
569
|
+
f"{out['matched_terms']} (ignoring {dropped}) and are ordered closest-first. "
|
|
570
|
+
f"A dropped word is usually the TARGET SYSTEM's vocabulary rather than AAT's. "
|
|
571
|
+
f"Read the top one with capabilities name=<name> action=<action> before "
|
|
572
|
+
f"rephrasing - rephrasing rarely helps here.")
|
|
573
|
+
if len(group) > 3 * limit:
|
|
574
|
+
out["hint"] = (
|
|
575
|
+
f"Too vague: {len(group)} actions match only {out['matched_terms']} "
|
|
576
|
+
f"(ignoring {dropped}), so this list is not an answer. Add a word that "
|
|
577
|
+
f"names what you want DONE (create, edit, run, list) "
|
|
578
|
+
+ ("" if name else "and pass name=<capability> to scope it ")
|
|
579
|
+
+ "and search again.")
|
|
580
|
+
return out
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
def action_help(name: str, action: str | None, kind: str | None = None) -> dict | None:
|
|
584
|
+
"""Compact 'what was I supposed to pass' for ONE call, used to enrich a failed
|
|
585
|
+
run (server._run). Returns None when the capability is unknown.
|
|
586
|
+
|
|
587
|
+
This is the cheapest fix in the chain: when a call fails with a bad flag or a
|
|
588
|
+
bad action name, the framework already holds the right answer at that exact
|
|
589
|
+
moment - it just never said it."""
|
|
590
|
+
entry, found_kind = _find(name, kind)
|
|
591
|
+
if entry is None:
|
|
592
|
+
return None
|
|
593
|
+
names = _action_names(entry)
|
|
594
|
+
if names and action and action not in names:
|
|
595
|
+
return {"of": entry["name"], "kind": found_kind, "unknown_action": action,
|
|
596
|
+
"action_count": len(names),
|
|
597
|
+
"did_you_mean": _suggest(action, names) or names[:15]}
|
|
598
|
+
args = entry.get("args")
|
|
599
|
+
if names:
|
|
600
|
+
for a in entry.get("actions") or []:
|
|
601
|
+
if a["name"] == action:
|
|
602
|
+
args = a.get("args")
|
|
603
|
+
break
|
|
604
|
+
else:
|
|
605
|
+
return None
|
|
606
|
+
return {"of": entry["name"], "kind": found_kind, "action": action,
|
|
607
|
+
"valid_args": [
|
|
608
|
+
{"name": s["name"], "type": s["type"], "required": s["required"]}
|
|
609
|
+
for s in _args_schema(args)
|
|
610
|
+
]}
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
def capabilities(kind: str | None = None, name: str | None = None,
|
|
614
|
+
action: str | None = None, search: str | None = None,
|
|
615
|
+
full: bool = False) -> dict:
|
|
616
|
+
"""Discover AAT capabilities, narrowest door first.
|
|
617
|
+
|
|
618
|
+
- search -> keyword search over actions (optionally within `name`)
|
|
619
|
+
- name + action -> that ONE action's arg schema
|
|
620
|
+
- name -> the full schema, or its action index if oversized
|
|
621
|
+
- neither -> the compact tool/agent/skill list (the router map),
|
|
622
|
+
trimmed unless `full` asks for the longer line
|
|
623
|
+
"""
|
|
624
|
+
tools, agents, skills = _scan_registry()
|
|
625
|
+
|
|
626
|
+
if search:
|
|
627
|
+
return _search_actions(search, kind=kind, name=name)
|
|
628
|
+
|
|
629
|
+
# An action without a capability name is still answerable: look it up across
|
|
630
|
+
# everything rather than refusing on a technicality.
|
|
631
|
+
if action and not name:
|
|
632
|
+
return _search_actions(action, kind=kind)
|
|
633
|
+
|
|
634
|
+
if name:
|
|
635
|
+
entry, found_kind = _find(name, kind)
|
|
636
|
+
if entry is None:
|
|
637
|
+
raise KeyError(f"no tool or agent named {name!r}")
|
|
638
|
+
if action:
|
|
639
|
+
return _one_action(entry, found_kind, action)
|
|
640
|
+
full = _full(entry, found_kind)
|
|
641
|
+
limit = _max_bytes()
|
|
642
|
+
size = len(json.dumps(full, ensure_ascii=False))
|
|
643
|
+
if limit and size > limit and entry.get("actions"):
|
|
644
|
+
return _degraded(entry, found_kind, size, limit)
|
|
645
|
+
return {"capability": full}
|
|
646
|
+
|
|
647
|
+
out: list[dict] = []
|
|
648
|
+
if kind in (None, "tool"):
|
|
649
|
+
out += [_compact(e, "tool", full) for e in tools if not e.get("error")]
|
|
650
|
+
if kind in (None, "agent"):
|
|
651
|
+
out += [_compact(e, "agent", full) for e in agents if not e.get("error")]
|
|
652
|
+
if kind in (None, "skill"):
|
|
653
|
+
out += [_compact(e, "skill", full) for e in skills
|
|
654
|
+
if not e.get("error")]
|
|
655
|
+
return {"count": len(out), "capabilities": out}
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
def run_tool(tool: str, action: str | None, args: dict[str, Any] | None) -> dict:
|
|
659
|
+
"""Execute a tool. args is a JSON object -> --flags via runner.flags_from
|
|
660
|
+
(dict/list values are JSON-encoded into ONE argv element; no shell). Host-only
|
|
661
|
+
tools are delegated to the host-runner when AAT_HOST_RUNNER_URL is set."""
|
|
662
|
+
# Wrap in a per-work-unit accounting span (no-op locally; the platform injects a
|
|
663
|
+
# sink that acquires an EE slot + emits TrackAction - spec P0.0-05 / seam S2).
|
|
664
|
+
with accounting.work_unit("tool", ws=_workspace_ctx.get(),
|
|
665
|
+
user=_user_ctx.get()) as wu:
|
|
666
|
+
wu["tool"] = tool
|
|
667
|
+
if action:
|
|
668
|
+
wu["action"] = action
|
|
669
|
+
if os.environ.get("AAT_HOST_RUNNER_URL") and _is_host_only("tool", tool):
|
|
670
|
+
return _delegate("tool", tool, action, args)
|
|
671
|
+
argv = ([action] if action else []) + runner.flags_from(args)
|
|
672
|
+
return runner.run_tool(tool, argv, env=_user_env())
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
def run_agent(agent: str, action: str | None, args: dict[str, Any] | None) -> dict:
|
|
676
|
+
refusal = _managed_turn_refusal(agent, action)
|
|
677
|
+
if refusal is not None:
|
|
678
|
+
return refusal
|
|
679
|
+
with accounting.work_unit("agent", ws=_workspace_ctx.get(),
|
|
680
|
+
user=_user_ctx.get()) as wu:
|
|
681
|
+
wu["agent"] = agent
|
|
682
|
+
if action:
|
|
683
|
+
wu["action"] = action
|
|
684
|
+
if os.environ.get("AAT_HOST_RUNNER_URL") and _is_host_only("agent", agent):
|
|
685
|
+
return _delegate("agent", agent, action, args)
|
|
686
|
+
argv = ([action] if action else []) + runner.flags_from(args)
|
|
687
|
+
return runner.run_agent(agent, argv, env=_user_env())
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
def get_skill(name: str) -> dict:
|
|
691
|
+
"""Return a skill's full markdown plus a metadata-only bundled-resource index
|
|
692
|
+
(model-decided skill loading — the substitute for harness auto-trigger; see spec 04).
|
|
693
|
+
A remote MCP client has no filesystem, so the index is how it discovers a skill's
|
|
694
|
+
references/scripts/assets; fetch one on demand with get_skill_resource."""
|
|
695
|
+
m = registry.get_skill(name) # raises KeyError if unknown
|
|
696
|
+
md = (m.path / "SKILL.md").read_text(encoding="utf-8")
|
|
697
|
+
return {"name": m.name, "content": md, "resources": resource_index(m.path)}
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
def get_skill_resource(name: str, path: str) -> dict:
|
|
701
|
+
"""Return one safe UTF-8 resource below references/, scripts/, or assets/ of a skill.
|
|
702
|
+
The path must come from get_skill's resource index; traversal, symlink escape, a
|
|
703
|
+
non-text file and an oversized file are all rejected (see tools/_lib/skill_resources)."""
|
|
704
|
+
m = registry.get_skill(name) # raises KeyError if unknown
|
|
705
|
+
return {"name": m.name, "resource": read_text_resource(m.path, path)}
|