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,578 @@
|
|
|
1
|
+
"""Pluggable credential backends, selected by the ``AAT_CREDS_BACKEND`` env var.
|
|
2
|
+
|
|
3
|
+
The framework's canonical secret identity is ``agents-and-tools:<tool>:<secret>``.
|
|
4
|
+
Every backend resolves the same ``(tool, secret)`` pair; only WHERE it reads from
|
|
5
|
+
changes. With ``AAT_CREDS_BACKEND`` unset the OS-native store is chosen for the
|
|
6
|
+
platform (see ``default_backend_name``), so no user on any of the three desktops has
|
|
7
|
+
to configure anything, and a Windows session behaves exactly as it always did.
|
|
8
|
+
|
|
9
|
+
windows - Windows Credential Manager via keyring (default on win32)
|
|
10
|
+
macos - macOS login Keychain via keyring (default on darwin)
|
|
11
|
+
linux - GNOME Keyring / KWallet over D-Bus via keyring (default elsewhere)
|
|
12
|
+
encrypted-file - one passphrase-encrypted file (``AAT_SECRETS_FILE``); the store
|
|
13
|
+
for a HEADLESS machine, where no OS keyring exists
|
|
14
|
+
env - a single JSON blob in ``AAT_SECRETS_JSON`` = {tool:{secret:val}}
|
|
15
|
+
file - a directory (``AAT_SECRETS_DIR``) of ``<tool>__<secret>`` files
|
|
16
|
+
and/or a ``secrets.json`` (k8s Secret / mounted-file friendly)
|
|
17
|
+
bridge - HTTP GET to a loopback host service wrapping the host's Cred Mgr
|
|
18
|
+
(a container on the laptop reads host secrets; nothing copied)
|
|
19
|
+
procesio - HTTP GET to a PROCESIO credential resolver, scoped to the active
|
|
20
|
+
(workspace, user); the multi-tenant platform backend (spec P0.0-08)
|
|
21
|
+
|
|
22
|
+
The four OWNED stores (windows / macos / linux / encrypted-file) are read/write, so
|
|
23
|
+
``set-credential.py`` works on every OS. The four BORROWED ones (env / file / bridge /
|
|
24
|
+
procesio) are READ-ONLY: those secrets are managed by a host or cluster and must never
|
|
25
|
+
be written from inside a container.
|
|
26
|
+
|
|
27
|
+
Every OS backend imports ``keyring`` lazily, inside the selected backend only, so this
|
|
28
|
+
module imports cleanly on a platform whose keyring backend is unavailable - which is
|
|
29
|
+
what lets a Linux container import the framework without a session bus.
|
|
30
|
+
"""
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
|
|
33
|
+
import json
|
|
34
|
+
import os
|
|
35
|
+
import re
|
|
36
|
+
import sys
|
|
37
|
+
import time
|
|
38
|
+
import urllib.error
|
|
39
|
+
import urllib.request
|
|
40
|
+
from pathlib import Path
|
|
41
|
+
from typing import Protocol
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class Backend(Protocol):
|
|
45
|
+
def get_optional(self, tool: str, secret: str) -> str | None: ...
|
|
46
|
+
def set(self, tool: str, secret: str, value: str) -> None: ...
|
|
47
|
+
def delete(self, tool: str, secret: str) -> None: ...
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class _ReadOnly:
|
|
51
|
+
"""Mixin: writes raise, so a container never pretends to own the secret store."""
|
|
52
|
+
|
|
53
|
+
name = "read-only"
|
|
54
|
+
|
|
55
|
+
def set(self, tool: str, secret: str, value: str) -> None:
|
|
56
|
+
raise RuntimeError(
|
|
57
|
+
f"credential backend {self.name!r} is read-only; manage secrets on the "
|
|
58
|
+
f"host/cluster, not from here")
|
|
59
|
+
|
|
60
|
+
def delete(self, tool: str, secret: str) -> None:
|
|
61
|
+
raise RuntimeError(
|
|
62
|
+
f"credential backend {self.name!r} is read-only; manage secrets on the "
|
|
63
|
+
f"host/cluster, not from here")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class WindowsBackend:
|
|
67
|
+
"""Windows Credential Manager via keyring. Service = agents-and-tools:<tool>."""
|
|
68
|
+
|
|
69
|
+
name = "windows"
|
|
70
|
+
NAMESPACE = "agents-and-tools"
|
|
71
|
+
|
|
72
|
+
def __init__(self) -> None:
|
|
73
|
+
import keyring # lazy: only when this backend is selected
|
|
74
|
+
backend = keyring.get_keyring()
|
|
75
|
+
tname = type(backend).__name__
|
|
76
|
+
if "WinVault" not in tname and "Windows" not in tname:
|
|
77
|
+
try:
|
|
78
|
+
from keyring.backends.Windows import WinVaultKeyring
|
|
79
|
+
keyring.set_keyring(WinVaultKeyring())
|
|
80
|
+
except Exception as e: # noqa: BLE001
|
|
81
|
+
raise RuntimeError(
|
|
82
|
+
f"keyring backend is {tname}, not Windows Credential Manager. "
|
|
83
|
+
f"The 'windows' creds backend requires Windows. ({e})") from e
|
|
84
|
+
self._kr = keyring
|
|
85
|
+
|
|
86
|
+
def _svc(self, tool: str) -> str:
|
|
87
|
+
return f"{self.NAMESPACE}:{tool}"
|
|
88
|
+
|
|
89
|
+
def get_optional(self, tool: str, secret: str) -> str | None:
|
|
90
|
+
return self._kr.get_password(self._svc(tool), secret)
|
|
91
|
+
|
|
92
|
+
def set(self, tool: str, secret: str, value: str) -> None:
|
|
93
|
+
self._kr.set_password(self._svc(tool), secret, value)
|
|
94
|
+
|
|
95
|
+
def delete(self, tool: str, secret: str) -> None:
|
|
96
|
+
try:
|
|
97
|
+
self._kr.delete_password(self._svc(tool), secret)
|
|
98
|
+
except self._kr.errors.PasswordDeleteError:
|
|
99
|
+
pass
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class MacKeychainBackend:
|
|
103
|
+
"""macOS login Keychain via keyring. Service = agents-and-tools:<tool>.
|
|
104
|
+
|
|
105
|
+
The macOS peer of WindowsBackend: same NAMESPACE and (tool, secret) identity, so a
|
|
106
|
+
Mac user's secrets live in the login Keychain exactly where a Windows user's live in
|
|
107
|
+
Credential Manager. Read/write (set-credential.py works). keyring's macOS backend is
|
|
108
|
+
imported lazily so this module still imports cleanly off-Mac."""
|
|
109
|
+
|
|
110
|
+
name = "macos"
|
|
111
|
+
NAMESPACE = "agents-and-tools"
|
|
112
|
+
|
|
113
|
+
def __init__(self) -> None:
|
|
114
|
+
# Use a DIRECT macOS backend instance. Do NOT call keyring.get_keyring()
|
|
115
|
+
# / set_keyring(): those trigger keyring's backend auto-detection, which
|
|
116
|
+
# evaluates the built-in Windows backend's `priority` classproperty — and
|
|
117
|
+
# that raises "Requires Windows and pywin32" on macOS. Talking to the
|
|
118
|
+
# macOS.Keyring instance directly sidesteps auto-detection entirely.
|
|
119
|
+
try:
|
|
120
|
+
from keyring.backends import macOS as _macos
|
|
121
|
+
from keyring import errors as _errors
|
|
122
|
+
except Exception as e: # noqa: BLE001
|
|
123
|
+
raise RuntimeError(
|
|
124
|
+
f"macOS Keychain keyring backend unavailable ({e}); "
|
|
125
|
+
f"the 'macos' creds backend requires macOS.") from e
|
|
126
|
+
self._kc = _macos.Keyring()
|
|
127
|
+
self._errors = _errors
|
|
128
|
+
|
|
129
|
+
def _svc(self, tool: str) -> str:
|
|
130
|
+
return f"{self.NAMESPACE}:{tool}"
|
|
131
|
+
|
|
132
|
+
def get_optional(self, tool: str, secret: str) -> str | None:
|
|
133
|
+
return self._kc.get_password(self._svc(tool), secret)
|
|
134
|
+
|
|
135
|
+
def set(self, tool: str, secret: str, value: str) -> None:
|
|
136
|
+
self._kc.set_password(self._svc(tool), secret, value)
|
|
137
|
+
|
|
138
|
+
def delete(self, tool: str, secret: str) -> None:
|
|
139
|
+
try:
|
|
140
|
+
self._kc.delete_password(self._svc(tool), secret)
|
|
141
|
+
except self._errors.PasswordDeleteError:
|
|
142
|
+
pass
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class LinuxSecretServiceBackend:
|
|
146
|
+
"""Linux desktop secret store via keyring. Service = agents-and-tools:<tool>.
|
|
147
|
+
|
|
148
|
+
The Linux peer of WindowsBackend / MacKeychainBackend: same NAMESPACE and
|
|
149
|
+
``(tool, secret)`` identity, so a Linux user's secrets live in GNOME Keyring or
|
|
150
|
+
KWallet exactly where a Windows user's live in Credential Manager. Read/write, so
|
|
151
|
+
``set-credential.py`` works.
|
|
152
|
+
|
|
153
|
+
Like the macOS backend, this talks to a DIRECT backend instance and never calls
|
|
154
|
+
``keyring.get_keyring()`` / ``set_keyring()``: auto-detection evaluates the built-in
|
|
155
|
+
Windows backend's ``priority`` classproperty, which raises off-Windows.
|
|
156
|
+
|
|
157
|
+
Availability is probed through each backend's ``priority`` classproperty, which is
|
|
158
|
+
keyring's own "can I run here" contract - it raises when the D-Bus Secret Service
|
|
159
|
+
(or KWallet) is not reachable. That is the normal case on a HEADLESS server: there
|
|
160
|
+
is no session bus, so no OS keyring exists to talk to. The error then names the
|
|
161
|
+
backends that do work without a desktop session rather than leaving the caller with
|
|
162
|
+
a D-Bus traceback."""
|
|
163
|
+
|
|
164
|
+
name = "linux"
|
|
165
|
+
NAMESPACE = "agents-and-tools"
|
|
166
|
+
|
|
167
|
+
# (module path, class name) in preference order. SecretService covers GNOME /
|
|
168
|
+
# freedesktop.org (the default on most distros); kwallet covers KDE.
|
|
169
|
+
_CANDIDATES = (
|
|
170
|
+
("keyring.backends.SecretService", "Keyring"),
|
|
171
|
+
("keyring.backends.kwallet", "DBusKeyring"),
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
def __init__(self) -> None:
|
|
175
|
+
try:
|
|
176
|
+
from keyring import errors as _errors
|
|
177
|
+
except Exception as e: # noqa: BLE001
|
|
178
|
+
raise RuntimeError(f"keyring is not installed ({e})") from e
|
|
179
|
+
self._errors = _errors
|
|
180
|
+
|
|
181
|
+
import importlib
|
|
182
|
+
|
|
183
|
+
attempts: list[str] = []
|
|
184
|
+
for mod_path, cls_name in self._CANDIDATES:
|
|
185
|
+
try:
|
|
186
|
+
cls = getattr(importlib.import_module(mod_path), cls_name)
|
|
187
|
+
cls.priority # noqa: B018 - keyring's own availability probe; raises when unusable
|
|
188
|
+
self._kr = cls()
|
|
189
|
+
self.backend_name = f"{mod_path}.{cls_name}"
|
|
190
|
+
return
|
|
191
|
+
except Exception as e: # noqa: BLE001 - try the next candidate
|
|
192
|
+
attempts.append(f"{mod_path}.{cls_name}: {e}")
|
|
193
|
+
raise RuntimeError(
|
|
194
|
+
"no Linux OS keyring is reachable (tried " + "; ".join(attempts) + "). "
|
|
195
|
+
"On a headless machine there is no session keyring: set "
|
|
196
|
+
"AAT_CREDS_BACKEND=encrypted-file (read/write, passphrase in "
|
|
197
|
+
"AAT_SECRETS_PASSPHRASE), or =file / =env for secrets managed by the "
|
|
198
|
+
"host or cluster.")
|
|
199
|
+
|
|
200
|
+
def _svc(self, tool: str) -> str:
|
|
201
|
+
return f"{self.NAMESPACE}:{tool}"
|
|
202
|
+
|
|
203
|
+
def get_optional(self, tool: str, secret: str) -> str | None:
|
|
204
|
+
return self._kr.get_password(self._svc(tool), secret)
|
|
205
|
+
|
|
206
|
+
def set(self, tool: str, secret: str, value: str) -> None:
|
|
207
|
+
self._kr.set_password(self._svc(tool), secret, value)
|
|
208
|
+
|
|
209
|
+
def delete(self, tool: str, secret: str) -> None:
|
|
210
|
+
try:
|
|
211
|
+
self._kr.delete_password(self._svc(tool), secret)
|
|
212
|
+
except self._errors.PasswordDeleteError:
|
|
213
|
+
pass
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
class EncryptedFileBackend:
|
|
217
|
+
"""A single passphrase-encrypted file, for a machine with no OS keyring.
|
|
218
|
+
|
|
219
|
+
The headless-Linux (and container-with-state) peer of the three OS stores: same
|
|
220
|
+
``(tool, secret)`` identity, READ/WRITE, so ``set-credential.py`` works where
|
|
221
|
+
GNOME Keyring and KWallet do not exist. Distinct from ``file`` / ``env``, which are
|
|
222
|
+
read-only views of secrets some host or cluster already manages.
|
|
223
|
+
|
|
224
|
+
Storage: one JSON envelope at ``AAT_SECRETS_FILE``
|
|
225
|
+
(default ``~/.config/agents-and-tools/secrets.enc``) holding a per-file scrypt salt
|
|
226
|
+
and a Fernet token over ``{tool: {secret: value}}``. The file is written 0600 and
|
|
227
|
+
replaced atomically, so a crash mid-write cannot leave a half-written store that
|
|
228
|
+
reads as an empty one.
|
|
229
|
+
|
|
230
|
+
The passphrase comes from ``AAT_SECRETS_PASSPHRASE``, or an interactive prompt ONLY
|
|
231
|
+
when stdin is a TTY. An agent runs with stdin closed, so prompting there would hang
|
|
232
|
+
forever instead of failing; the error says which variable to set."""
|
|
233
|
+
|
|
234
|
+
name = "encrypted-file"
|
|
235
|
+
VERSION = 1
|
|
236
|
+
SCRYPT_N = 2 ** 15
|
|
237
|
+
SCRYPT_R = 8
|
|
238
|
+
SCRYPT_P = 1
|
|
239
|
+
|
|
240
|
+
def __init__(self) -> None:
|
|
241
|
+
self._path = Path(
|
|
242
|
+
os.environ.get("AAT_SECRETS_FILE")
|
|
243
|
+
or Path.home() / ".config" / "agents-and-tools" / "secrets.enc")
|
|
244
|
+
self._cache: dict | None = None
|
|
245
|
+
|
|
246
|
+
# --- crypto ----------------------------------------------------------
|
|
247
|
+
|
|
248
|
+
@staticmethod
|
|
249
|
+
def _passphrase() -> str:
|
|
250
|
+
pw = os.environ.get("AAT_SECRETS_PASSPHRASE")
|
|
251
|
+
if pw:
|
|
252
|
+
return pw
|
|
253
|
+
if sys.stdin is not None and sys.stdin.isatty():
|
|
254
|
+
import getpass
|
|
255
|
+
pw = getpass.getpass("AAT secrets passphrase: ")
|
|
256
|
+
if pw:
|
|
257
|
+
return pw
|
|
258
|
+
raise RuntimeError(
|
|
259
|
+
"no passphrase for the encrypted-file credential store: set "
|
|
260
|
+
"AAT_SECRETS_PASSPHRASE (a non-interactive run cannot be prompted)")
|
|
261
|
+
|
|
262
|
+
def _fernet(self, salt: bytes):
|
|
263
|
+
try:
|
|
264
|
+
from cryptography.fernet import Fernet
|
|
265
|
+
from cryptography.hazmat.primitives.kdf.scrypt import Scrypt
|
|
266
|
+
except Exception as e: # noqa: BLE001
|
|
267
|
+
raise RuntimeError(
|
|
268
|
+
f"the encrypted-file credential backend needs the 'cryptography' "
|
|
269
|
+
f"package ({e}); install it or use AAT_CREDS_BACKEND=file/env") from e
|
|
270
|
+
import base64
|
|
271
|
+
key = Scrypt(salt=salt, length=32, n=self.SCRYPT_N, r=self.SCRYPT_R,
|
|
272
|
+
p=self.SCRYPT_P).derive(self._passphrase().encode("utf-8"))
|
|
273
|
+
return Fernet(base64.urlsafe_b64encode(key))
|
|
274
|
+
|
|
275
|
+
# --- store -----------------------------------------------------------
|
|
276
|
+
|
|
277
|
+
def _load(self) -> dict:
|
|
278
|
+
if self._cache is not None:
|
|
279
|
+
return self._cache
|
|
280
|
+
if not self._path.exists():
|
|
281
|
+
self._cache = {}
|
|
282
|
+
return self._cache
|
|
283
|
+
import base64
|
|
284
|
+
try:
|
|
285
|
+
env = json.loads(self._path.read_text(encoding="utf-8"))
|
|
286
|
+
except ValueError as e:
|
|
287
|
+
raise RuntimeError(f"{self._path} is not a valid secret store: {e}") from e
|
|
288
|
+
if int(env.get("version", 0)) != self.VERSION:
|
|
289
|
+
raise RuntimeError(
|
|
290
|
+
f"{self._path}: unsupported store version {env.get('version')!r}")
|
|
291
|
+
f = self._fernet(base64.b64decode(env["salt"]))
|
|
292
|
+
try:
|
|
293
|
+
plain = f.decrypt(env["data"].encode("ascii"))
|
|
294
|
+
except Exception as e: # noqa: BLE001 - InvalidToken and friends
|
|
295
|
+
raise RuntimeError(
|
|
296
|
+
f"cannot decrypt {self._path}: wrong passphrase, or the file was "
|
|
297
|
+
f"written with a different one ({type(e).__name__})") from e
|
|
298
|
+
self._cache = json.loads(plain.decode("utf-8"))
|
|
299
|
+
return self._cache
|
|
300
|
+
|
|
301
|
+
def _save(self, data: dict) -> None:
|
|
302
|
+
import base64
|
|
303
|
+
salt = os.urandom(16) # fresh salt per write: never reuse a KDF salt
|
|
304
|
+
blob = self._fernet(salt).encrypt(
|
|
305
|
+
json.dumps(data, ensure_ascii=False).encode("utf-8"))
|
|
306
|
+
env = {"version": self.VERSION, "kdf": "scrypt",
|
|
307
|
+
"n": self.SCRYPT_N, "r": self.SCRYPT_R, "p": self.SCRYPT_P,
|
|
308
|
+
"salt": base64.b64encode(salt).decode("ascii"),
|
|
309
|
+
"data": blob.decode("ascii")}
|
|
310
|
+
self._path.parent.mkdir(parents=True, exist_ok=True)
|
|
311
|
+
tmp = self._path.with_suffix(self._path.suffix + ".tmp")
|
|
312
|
+
tmp.write_text(json.dumps(env), encoding="utf-8")
|
|
313
|
+
try:
|
|
314
|
+
os.chmod(tmp, 0o600) # no-op semantics on Windows; correct on POSIX
|
|
315
|
+
except OSError:
|
|
316
|
+
pass
|
|
317
|
+
os.replace(tmp, self._path) # atomic: a crash never leaves a partial store
|
|
318
|
+
self._cache = data
|
|
319
|
+
|
|
320
|
+
# --- Backend protocol -------------------------------------------------
|
|
321
|
+
|
|
322
|
+
def get_optional(self, tool: str, secret: str) -> str | None:
|
|
323
|
+
v = (self._load().get(tool) or {}).get(secret)
|
|
324
|
+
return str(v) if v is not None else None
|
|
325
|
+
|
|
326
|
+
def set(self, tool: str, secret: str, value: str) -> None:
|
|
327
|
+
data = dict(self._load())
|
|
328
|
+
data[tool] = {**(data.get(tool) or {}), secret: value}
|
|
329
|
+
self._save(data)
|
|
330
|
+
|
|
331
|
+
def delete(self, tool: str, secret: str) -> None:
|
|
332
|
+
data = dict(self._load())
|
|
333
|
+
bucket = dict(data.get(tool) or {})
|
|
334
|
+
if bucket.pop(secret, None) is None:
|
|
335
|
+
return
|
|
336
|
+
if bucket:
|
|
337
|
+
data[tool] = bucket
|
|
338
|
+
else:
|
|
339
|
+
data.pop(tool, None)
|
|
340
|
+
self._save(data)
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
class EnvJsonBackend(_ReadOnly):
|
|
344
|
+
"""Secrets from one JSON blob in AAT_SECRETS_JSON = {"tool": {"secret": "val"}}.
|
|
345
|
+
Simplest for docker-compose (pass a single env var)."""
|
|
346
|
+
|
|
347
|
+
name = "env"
|
|
348
|
+
|
|
349
|
+
def __init__(self) -> None:
|
|
350
|
+
raw = (os.environ.get("AAT_SECRETS_JSON") or "").strip()
|
|
351
|
+
try:
|
|
352
|
+
self._data = json.loads(raw) if raw else {}
|
|
353
|
+
except ValueError as e:
|
|
354
|
+
raise RuntimeError(f"AAT_SECRETS_JSON is not valid JSON: {e}") from e
|
|
355
|
+
|
|
356
|
+
def get_optional(self, tool: str, secret: str) -> str | None:
|
|
357
|
+
v = (self._data.get(tool) or {}).get(secret)
|
|
358
|
+
return str(v) if v is not None else None
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
class FileSecretBackend(_ReadOnly):
|
|
362
|
+
"""Secrets from a directory (AAT_SECRETS_DIR, default /run/secrets/aat) of
|
|
363
|
+
``<tool>__<secret>`` files (k8s Secret mounts each key as a file) and/or a
|
|
364
|
+
``secrets.json`` in the same dir.
|
|
365
|
+
|
|
366
|
+
Multi-user: when AAT_USER_ID is set, a per-user subdir ``<dir>/<user>/`` is searched
|
|
367
|
+
FIRST, then the shared dir — so each user's mounted Secret isolates their
|
|
368
|
+
credentials (spec 08). Unset = single shared dir, exactly as before."""
|
|
369
|
+
|
|
370
|
+
name = "file"
|
|
371
|
+
|
|
372
|
+
def __init__(self) -> None:
|
|
373
|
+
self._dir = Path(os.environ.get("AAT_SECRETS_DIR") or "/run/secrets/aat")
|
|
374
|
+
|
|
375
|
+
@staticmethod
|
|
376
|
+
def _safe(v: str) -> str | None:
|
|
377
|
+
s = re.sub(r"[^0-9A-Za-z._-]+", "-", (v or "").strip()).strip("-._")
|
|
378
|
+
return s if s and s not in (".", "..") else None
|
|
379
|
+
|
|
380
|
+
def _dirs(self) -> list[Path]:
|
|
381
|
+
"""Search order, most specific first, mirroring userdata's ``(ws, user)``
|
|
382
|
+
layout (spec P0.0-01): ``ws/<ws>/<user>`` -> ``<user>`` -> ``ws/<ws>`` ->
|
|
383
|
+
shared. Unset AAT_WORKSPACE_ID/AAT_USER_ID falls straight through to the shared
|
|
384
|
+
dir, exactly the historical behaviour."""
|
|
385
|
+
dirs: list[Path] = []
|
|
386
|
+
ws = self._safe(os.environ.get("AAT_WORKSPACE_ID") or "")
|
|
387
|
+
uid = self._safe(os.environ.get("AAT_USER_ID") or "")
|
|
388
|
+
if ws and uid:
|
|
389
|
+
dirs.append(self._dir / "ws" / ws / uid) # per-(ws,user), highest priority
|
|
390
|
+
if uid:
|
|
391
|
+
dirs.append(self._dir / uid) # per-user
|
|
392
|
+
if ws:
|
|
393
|
+
dirs.append(self._dir / "ws" / ws) # per-workspace (shared in WS)
|
|
394
|
+
dirs.append(self._dir) # shared fallback
|
|
395
|
+
return dirs
|
|
396
|
+
|
|
397
|
+
def get_optional(self, tool: str, secret: str) -> str | None:
|
|
398
|
+
for d in self._dirs():
|
|
399
|
+
f = d / f"{tool}__{secret}"
|
|
400
|
+
if f.exists():
|
|
401
|
+
return f.read_text(encoding="utf-8").strip() or None
|
|
402
|
+
jf = d / "secrets.json"
|
|
403
|
+
if jf.exists():
|
|
404
|
+
try:
|
|
405
|
+
v = (json.loads(jf.read_text(encoding="utf-8")).get(tool) or {}).get(secret)
|
|
406
|
+
except ValueError:
|
|
407
|
+
v = None
|
|
408
|
+
if v is not None:
|
|
409
|
+
return str(v)
|
|
410
|
+
return None
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
class BridgeBackend(_ReadOnly):
|
|
414
|
+
"""HTTP GET to a loopback host service that wraps Windows Credential Manager.
|
|
415
|
+
Lets a container on the laptop read host secrets without copying them (infra I1).
|
|
416
|
+
AAT_CREDS_BRIDGE_URL (default http://host.docker.internal:8903) + a bearer token
|
|
417
|
+
in AAT_CREDS_BRIDGE_TOKEN."""
|
|
418
|
+
|
|
419
|
+
name = "bridge"
|
|
420
|
+
|
|
421
|
+
def __init__(self) -> None:
|
|
422
|
+
self._url = (os.environ.get("AAT_CREDS_BRIDGE_URL")
|
|
423
|
+
or "http://host.docker.internal:8903").rstrip("/")
|
|
424
|
+
self._token = os.environ.get("AAT_CREDS_BRIDGE_TOKEN", "")
|
|
425
|
+
# In-container cache. The container's readiness scan checks every secret over
|
|
426
|
+
# the network and the model calls capabilities repeatedly; secrets don't change
|
|
427
|
+
# mid-session, so cache with a short TTL (AAT_CREDS_BRIDGE_TTL seconds, 0 = off).
|
|
428
|
+
# The value stays in memory only - already fetched on use.
|
|
429
|
+
self._cache: dict = {}
|
|
430
|
+
self._ttl = float(os.environ.get("AAT_CREDS_BRIDGE_TTL", "60") or 0)
|
|
431
|
+
|
|
432
|
+
def get_optional(self, tool: str, secret: str) -> str | None:
|
|
433
|
+
if self._ttl > 0:
|
|
434
|
+
hit = self._cache.get((tool, secret))
|
|
435
|
+
if hit is not None and hit[1] > time.monotonic():
|
|
436
|
+
return hit[0]
|
|
437
|
+
val = self._fetch(tool, secret)
|
|
438
|
+
if self._ttl > 0:
|
|
439
|
+
self._cache[(tool, secret)] = (val, time.monotonic() + self._ttl)
|
|
440
|
+
return val
|
|
441
|
+
|
|
442
|
+
def _fetch(self, tool: str, secret: str) -> str | None:
|
|
443
|
+
req = urllib.request.Request(
|
|
444
|
+
f"{self._url}/secret/{tool}/{secret}",
|
|
445
|
+
headers={"Authorization": f"Bearer {self._token}"} if self._token else {})
|
|
446
|
+
try:
|
|
447
|
+
with urllib.request.urlopen(req, timeout=5) as resp: # noqa: S310 (loopback)
|
|
448
|
+
body = resp.read().decode("utf-8").strip()
|
|
449
|
+
return body or None
|
|
450
|
+
except urllib.error.HTTPError as e:
|
|
451
|
+
# 404 is the ONE quiet outcome: the secret is genuinely absent, which
|
|
452
|
+
# is what get_optional promises to return None for. Every other code
|
|
453
|
+
# means "we could not answer the question" and must be loud - a
|
|
454
|
+
# refusal or an outage reported as None reaches the caller as
|
|
455
|
+
# "missing credential; run set-credential", sending someone to fix a
|
|
456
|
+
# store that is fine while the real cause goes unmentioned.
|
|
457
|
+
if e.code == 404:
|
|
458
|
+
return None
|
|
459
|
+
if e.code == 401:
|
|
460
|
+
raise RuntimeError(
|
|
461
|
+
f"creds bridge rejected the bearer token ({self._url}); "
|
|
462
|
+
"check AAT_CREDS_BRIDGE_TOKEN, or re-issue it with "
|
|
463
|
+
"`creds-bridge issue-token --force` and restart the bridge")
|
|
464
|
+
if e.code == 403:
|
|
465
|
+
raise RuntimeError(
|
|
466
|
+
f"creds bridge policy denies {tool}:{secret} ({self._url}); "
|
|
467
|
+
"widen 'allow' in the bridge's policy.json, or the host's "
|
|
468
|
+
"audit log will show the denial")
|
|
469
|
+
raise
|
|
470
|
+
except urllib.error.URLError as e:
|
|
471
|
+
raise RuntimeError(
|
|
472
|
+
f"creds bridge unreachable at {self._url} ({e.reason}); start it "
|
|
473
|
+
"on the host with `creds-bridge start`, or unset "
|
|
474
|
+
"AAT_CREDS_BACKEND to use this machine's own vault")
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
class ProcesioBackend(_ReadOnly):
|
|
478
|
+
"""Resolve a secret from the PROCESIO credential store for the active
|
|
479
|
+
``(workspace, user)`` (spec P0.0-08). Structurally identical to ``BridgeBackend``:
|
|
480
|
+
a read-only, TTL-cached HTTP GET to a resolver endpoint. The endpoint maps AAT's
|
|
481
|
+
``(tool, secret)`` identity to a PROCESIO ``CREDENTIALS`` row in the caller's
|
|
482
|
+
workspace and returns the decrypted value; nothing is written from a worker.
|
|
483
|
+
|
|
484
|
+
Config: ``AAT_PROCESIO_CREDS_URL`` (resolver base), ``AAT_PROCESIO_CREDS_TOKEN``
|
|
485
|
+
(bearer), ``AAT_CREDS_PROCESIO_TTL`` (cache seconds, default 60). The active
|
|
486
|
+
``(workspace, user)`` are sent as ``X-AAT-Workspace`` / ``X-AAT-User`` headers
|
|
487
|
+
(server-established env, item P0.0-01), so the endpoint scopes the lookup - incl.
|
|
488
|
+
the personal-workspace ``(WS=Empty, User)`` case. Import-safe on any OS."""
|
|
489
|
+
|
|
490
|
+
name = "procesio"
|
|
491
|
+
|
|
492
|
+
def __init__(self) -> None:
|
|
493
|
+
self._url = (os.environ.get("AAT_PROCESIO_CREDS_URL")
|
|
494
|
+
or "http://localhost:8904").rstrip("/")
|
|
495
|
+
self._token = os.environ.get("AAT_PROCESIO_CREDS_TOKEN", "")
|
|
496
|
+
self._cache: dict = {}
|
|
497
|
+
self._ttl = float(os.environ.get("AAT_CREDS_PROCESIO_TTL", "60") or 0)
|
|
498
|
+
|
|
499
|
+
def _headers(self) -> dict:
|
|
500
|
+
h = {}
|
|
501
|
+
if self._token:
|
|
502
|
+
h["Authorization"] = f"Bearer {self._token}"
|
|
503
|
+
ws = (os.environ.get("AAT_WORKSPACE_ID") or "").strip()
|
|
504
|
+
uid = (os.environ.get("AAT_USER_ID") or "").strip()
|
|
505
|
+
if ws:
|
|
506
|
+
h["X-AAT-Workspace"] = ws
|
|
507
|
+
if uid:
|
|
508
|
+
h["X-AAT-User"] = uid
|
|
509
|
+
return h
|
|
510
|
+
|
|
511
|
+
def get_optional(self, tool: str, secret: str) -> str | None:
|
|
512
|
+
# Cache key includes (ws,user) so a pooled worker serving many tenants never
|
|
513
|
+
# returns one tenant's secret to another.
|
|
514
|
+
ck = (os.environ.get("AAT_WORKSPACE_ID", ""), os.environ.get("AAT_USER_ID", ""),
|
|
515
|
+
tool, secret)
|
|
516
|
+
if self._ttl > 0:
|
|
517
|
+
hit = self._cache.get(ck)
|
|
518
|
+
if hit is not None and hit[1] > time.monotonic():
|
|
519
|
+
return hit[0]
|
|
520
|
+
val = self._fetch(tool, secret)
|
|
521
|
+
if self._ttl > 0:
|
|
522
|
+
self._cache[ck] = (val, time.monotonic() + self._ttl)
|
|
523
|
+
return val
|
|
524
|
+
|
|
525
|
+
def _fetch(self, tool: str, secret: str) -> str | None:
|
|
526
|
+
req = urllib.request.Request(
|
|
527
|
+
f"{self._url}/credential/{tool}/{secret}", headers=self._headers())
|
|
528
|
+
try:
|
|
529
|
+
with urllib.request.urlopen(req, timeout=10) as resp: # noqa: S310
|
|
530
|
+
body = resp.read().decode("utf-8").strip()
|
|
531
|
+
return body or None
|
|
532
|
+
except urllib.error.HTTPError as e:
|
|
533
|
+
if e.code == 404:
|
|
534
|
+
return None
|
|
535
|
+
raise
|
|
536
|
+
except urllib.error.URLError:
|
|
537
|
+
return None
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
_ALIASES = {
|
|
541
|
+
"windows": "windows", "winvault": "windows", "win32": "windows",
|
|
542
|
+
"macos": "macos", "mac": "macos", "keychain": "macos", "osx": "macos", "darwin": "macos",
|
|
543
|
+
"linux": "linux", "secretservice": "linux", "secret-service": "linux",
|
|
544
|
+
"kwallet": "linux", "gnome-keyring": "linux",
|
|
545
|
+
"encrypted-file": "encrypted-file", "encryptedfile": "encrypted-file",
|
|
546
|
+
"encrypted": "encrypted-file",
|
|
547
|
+
"env": "env", "envjson": "env", "env-json": "env",
|
|
548
|
+
"file": "file", "file-secret": "file", "filesecret": "file",
|
|
549
|
+
"bridge": "bridge",
|
|
550
|
+
"procesio": "procesio",
|
|
551
|
+
}
|
|
552
|
+
_CTORS = {"windows": WindowsBackend, "macos": MacKeychainBackend,
|
|
553
|
+
"linux": LinuxSecretServiceBackend, "encrypted-file": EncryptedFileBackend,
|
|
554
|
+
"env": EnvJsonBackend, "file": FileSecretBackend, "bridge": BridgeBackend,
|
|
555
|
+
"procesio": ProcesioBackend}
|
|
556
|
+
|
|
557
|
+
# Every backend name a caller may pass, in one place, so the factory's error message
|
|
558
|
+
# cannot drift from what the factory actually accepts (it used to be a hand-kept
|
|
559
|
+
# literal that already omitted 'macos').
|
|
560
|
+
KNOWN = tuple(sorted(_CTORS))
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
def default_backend_name() -> str:
|
|
564
|
+
"""The backend used when AAT_CREDS_BACKEND is unset: the OS-native secret store.
|
|
565
|
+
|
|
566
|
+
macOS -> login Keychain; Windows (incl. Claude Code) -> Credential Manager;
|
|
567
|
+
everything else -> the Linux desktop keyring. A function, not a module constant,
|
|
568
|
+
so a test can exercise the mapping for a platform it is not running on."""
|
|
569
|
+
return {"darwin": "macos", "win32": "windows"}.get(sys.platform, "linux")
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
def make(name: str | None) -> Backend:
|
|
573
|
+
requested = (name or "").strip().lower() or default_backend_name()
|
|
574
|
+
key = _ALIASES.get(requested)
|
|
575
|
+
if key is None:
|
|
576
|
+
raise ValueError(
|
|
577
|
+
f"unknown AAT_CREDS_BACKEND {name!r}; use one of: " + ", ".join(KNOWN))
|
|
578
|
+
return _CTORS[key]() # type: ignore[return-value]
|