@atmem/architect 0.0.0-stage → 0.2.0-alpha.4.1
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.
- package/CONSTITUTION.md +144 -0
- package/README.md +33 -2
- package/agent-skills/discovery/SKILL.md +48 -0
- package/agent-skills/discovery/topics.json +139 -0
- package/agent-skills/generation-capabilities.json +760 -0
- package/agent-skills/service-lifecycle.json +21 -0
- package/agent-skills/specialists/architecture/SKILL.md +15 -0
- package/agent-skills/specialists/aws/SKILL.md +17 -0
- package/agent-skills/specialists/azure/SKILL.md +7 -0
- package/agent-skills/specialists/composition/SKILL.md +17 -0
- package/agent-skills/specialists/devops/SKILL.md +10 -0
- package/agent-skills/specialists/finops/SKILL.md +7 -0
- package/agent-skills/specialists/gcp/SKILL.md +7 -0
- package/agent-skills/specialists/ibm/SKILL.md +7 -0
- package/agent-skills/specialists/manifest.json +13 -0
- package/agent-skills/specialists/pulumi/SKILL.md +7 -0
- package/agent-skills/specialists/security/SKILL.md +7 -0
- package/agent-skills/specialists/terraform/SKILL.md +14 -0
- package/agent-skills/upstream/aws/LICENSE +175 -0
- package/agent-skills/upstream/aws/SKILL.md +125 -0
- package/agent-skills/upstream/azure/LICENSE +21 -0
- package/agent-skills/upstream/azure/SKILL.md +387 -0
- package/agent-skills/upstream/gcp/LICENSE +202 -0
- package/agent-skills/upstream/gcp/SKILL.md +159 -0
- package/agent-skills/upstream/manifest.json +57 -0
- package/agent-skills/upstream/pulumi/LICENSE +201 -0
- package/agent-skills/upstream/pulumi/SKILL.md +501 -0
- package/agent-skills/upstream/terraform/LICENSE +373 -0
- package/agent-skills/upstream/terraform/SKILL.md +316 -0
- package/agent-skills/workflows/workflows.json +601 -0
- package/cli/architect.mjs +3 -0
- package/cli/runtime.mjs +115 -0
- package/dist/assets/html2canvas.esm-QH1iLAAe.js +22 -0
- package/dist/assets/index-B97MkVMs.css +1 -0
- package/dist/assets/index-qtCM2D7O.js +21271 -0
- package/dist/assets/index.es-C6C0sneB.js +18 -0
- package/dist/assets/purify.es-CAi2OJFm.js +3 -0
- package/dist/assets/visual-export-DjbjgQbA.js +173 -0
- package/dist/favicon.svg +2 -0
- package/dist/fonts/DM-Sans-OFL.txt +93 -0
- package/dist/fonts/Manrope-OFL.txt +93 -0
- package/dist/fonts/NotoSans-Regular.ttf +0 -0
- package/dist/fonts/OFL.txt +94 -0
- package/dist/fonts/dm-sans-latin-wght-normal.woff2 +0 -0
- package/dist/fonts/manrope-latin-wght-normal.woff2 +0 -0
- package/dist/index.html +4 -0
- package/dist/licenses/aws-architect-LICENSE.txt +17 -0
- package/dist/licenses/aws-mcp-LICENSE.txt +175 -0
- package/dist/licenses/aws-mcp-NOTICE.txt +1 -0
- package/dist/licenses/cloud-emulation-notices.txt +36619 -0
- package/dist/licenses/dependency-notices.txt +6379 -0
- package/dist/licenses/emulation-notices.txt +717 -0
- package/dist/licenses/github-copilot-sdk-LICENSE.txt +21 -0
- package/dist/licenses/memory-dependency-notices.txt +3319 -0
- package/dist/licenses/openarchflow-LICENSE.txt +21 -0
- package/dist/licenses/python-dependency-notices.txt +11951 -0
- package/docs/upstream-lock.json +26 -0
- package/knowledge/engineering-practices.json +536 -0
- package/package.json +30 -4
- package/packaging/uv-release-lock.json +54 -0
- package/public/licenses/aws-architect-LICENSE.txt +17 -0
- package/public/licenses/aws-mcp-LICENSE.txt +175 -0
- package/public/licenses/aws-mcp-NOTICE.txt +1 -0
- package/public/licenses/cloud-emulation-notices.txt +36619 -0
- package/public/licenses/dependency-notices.txt +6379 -0
- package/public/licenses/emulation-notices.txt +717 -0
- package/public/licenses/github-copilot-sdk-LICENSE.txt +21 -0
- package/public/licenses/memory-dependency-notices.txt +3319 -0
- package/public/licenses/openarchflow-LICENSE.txt +21 -0
- package/public/licenses/python-dependency-notices.txt +11951 -0
- package/scripts/terraform-render.mjs +8 -0
- package/server/__init__.py +0 -0
- package/server/abstraction.py +28 -0
- package/server/agent_runtime.py +153 -0
- package/server/app.py +257 -0
- package/server/architect.py +112 -0
- package/server/architecture_activity.py +67 -0
- package/server/attachments.py +101 -0
- package/server/cloud-emulation-requirements.txt +29 -0
- package/server/codex_app_server.py +219 -0
- package/server/codex_engineering_backend.py +266 -0
- package/server/codex_worker_policy.py +170 -0
- package/server/contracts.py +315 -0
- package/server/copilot_worker.py +16 -0
- package/server/dependency_mirror.py +54 -0
- package/server/design_patch.py +43 -0
- package/server/emulation-requirements.txt +8 -0
- package/server/emulation_adapters.py +20 -0
- package/server/emulation_routes.py +98 -0
- package/server/emulation_worker.py +351 -0
- package/server/engineering_artifacts.py +215 -0
- package/server/engineering_assets/application-runtime.json +4372 -0
- package/server/engineering_assets/architecture_work.schema.json +79 -0
- package/server/engineering_assets/materialize_runtime.py +62 -0
- package/server/engineering_assets/prepare_tools.py +96 -0
- package/server/engineering_assets/sql_validation.py +59 -0
- package/server/engineering_contexts.py +120 -0
- package/server/engineering_delivery.py +210 -0
- package/server/engineering_finalization.py +210 -0
- package/server/engineering_handoff.py +163 -0
- package/server/engineering_jobs.py +206 -0
- package/server/engineering_knowledge.py +75 -0
- package/server/engineering_reconciliation.py +159 -0
- package/server/engineering_routes.py +469 -0
- package/server/engineering_sessions.py +273 -0
- package/server/engineering_tools.py +166 -0
- package/server/generation_lint.py +18 -0
- package/server/local_providers.py +181 -0
- package/server/local_validation.py +236 -0
- package/server/memory-requirements.lock +181 -0
- package/server/memory-requirements.txt +6 -0
- package/server/memory_routes.py +82 -0
- package/server/memory_service.py +273 -0
- package/server/memory_worker.py +66 -0
- package/server/openai_voice.py +80 -0
- package/server/packaged_app.py +9 -0
- package/server/pricing.py +84 -0
- package/server/process_control_observation.py +31 -0
- package/server/prompts.py +123 -0
- package/server/public_faq_emulation_worker.py +44 -0
- package/server/requirements.lock +1618 -0
- package/server/requirements.txt +68 -0
- package/server/runtime_dependency_locks.py +27 -0
- package/server/runtime_evidence.py +93 -0
- package/server/settings.py +14 -0
- package/server/skills.py +103 -0
- package/server/storage_emulation_worker.py +160 -0
- package/server/structured_emulation_worker.py +48 -0
- package/server/terraform_routes.py +118 -0
- package/server/upstream/__init__.py +0 -0
- package/server/upstream/agent/__init__.py +1 -0
- package/server/upstream/agent/aws_architect.py +600 -0
- package/server/upstream/agent/config/__init__.py +1 -0
- package/server/upstream/agent/config/agent_config.py +82 -0
- package/server/upstream/agent/config/prompts.py +138 -0
- package/server/upstream/agent/rate_limiter.py +62 -0
- package/server/upstream/utils/__init__.py +1 -0
- package/server/upstream/utils/file_writer.py +43 -0
- package/server/validation_applicability.py +85 -0
- package/server/validation_jobs.py +252 -0
- package/server/validation_workers.py +48 -0
- package/server/voice_routes.py +91 -0
- package/server/voice_worker.py +26 -0
- package/specs/028-convergence-evaluation/evidence/20261110-ibm-invoice-native/registry-structured/qualification.json +72 -0
- package/specs/028-convergence-evaluation/evidence/20261110-invoice-runtime/durable-current/receipt.json +61 -0
- package/specs/029-general-purpose-engine/evidence/20261111-runtime-dependencies/sdk/receipt.json +22 -0
- package/src/ArchitectureActivity.jsx +54 -0
- package/src/ArchitectureWorkPanel.jsx +46 -0
- package/src/ArtifactChecks.jsx +49 -0
- package/src/BlockRequirements.jsx +13 -0
- package/src/BrainActivity.jsx +11 -0
- package/src/ChatMessage.jsx +19 -0
- package/src/ChatResizeHandle.jsx +6 -0
- package/src/CodePreview.jsx +8 -0
- package/src/ComponentReview.jsx +31 -0
- package/src/DeliveryViews.jsx +59 -0
- package/src/EmulationPanel.jsx +44 -0
- package/src/EngagementViews.jsx +385 -0
- package/src/EngineeringPanel.jsx +151 -0
- package/src/ImplementationDelivery.jsx +55 -0
- package/src/JourneyViews.jsx +400 -0
- package/src/MemoryPanel.jsx +46 -0
- package/src/OpenAIVoicePanel.jsx +65 -0
- package/src/OutputsView.jsx +65 -0
- package/src/TerraformView.jsx +57 -0
- package/src/WorkbenchDialogs.jsx +532 -0
- package/src/activity-presentation.mjs +28 -0
- package/src/ai-qualification-scenarios.mjs +31 -0
- package/src/approval-application-files.mjs +32 -0
- package/src/approval-applications.mjs +82 -0
- package/src/approval-spec-kit.mjs +30 -0
- package/src/architecture-activity.css +28 -0
- package/src/architecture-activity.mjs +63 -0
- package/src/architecture-work.mjs +176 -0
- package/src/artifact-work.mjs +103 -0
- package/src/async-documents.mjs +191 -0
- package/src/atflow.css +1140 -0
- package/src/atforma.css +748 -0
- package/src/atmem-tokens.css +79 -0
- package/src/aws-preflight.mjs +60 -0
- package/src/aws-public-faq.mjs +102 -0
- package/src/aws-validation-scenarios.mjs +10 -0
- package/src/aws-validation.mjs +48 -0
- package/src/azure-plan-mocks.mjs +25 -0
- package/src/azure-structured.mjs +133 -0
- package/src/bedrock-summary.mjs +152 -0
- package/src/bounded-rag.mjs +60 -0
- package/src/brand.css +9 -0
- package/src/canvas-view.mjs +28 -0
- package/src/capability-composition.mjs +44 -0
- package/src/chat-attachments.mjs +13 -0
- package/src/cloud-provider-locks.mjs +9 -0
- package/src/cloud-storage-scenarios.mjs +2 -0
- package/src/component-review.mjs +55 -0
- package/src/composition-spec-kit.mjs +30 -0
- package/src/consultation-context.mjs +15 -0
- package/src/consultation.mjs +52 -0
- package/src/container-contracts.mjs +5 -0
- package/src/container-inspection.mjs +75 -0
- package/src/container-runtime.mjs +30 -0
- package/src/container-security-inspection.mjs +49 -0
- package/src/container-terraform.mjs +109 -0
- package/src/conversation.mjs +17 -0
- package/src/core.mjs +863 -0
- package/src/cross-cloud-storage.mjs +100 -0
- package/src/delivery-capabilities.mjs +25 -0
- package/src/delivery.mjs +58 -0
- package/src/deployment-ownership.mjs +10 -0
- package/src/deployment-region.mjs +11 -0
- package/src/derive.mjs +31 -0
- package/src/design-build-flow.mjs +10 -0
- package/src/diagram-attention.mjs +24 -0
- package/src/discovery.mjs +359 -0
- package/src/document.mjs +170 -0
- package/src/emulation-feedback.mjs +61 -0
- package/src/emulation-guidance.mjs +37 -0
- package/src/engagement.mjs +274 -0
- package/src/engineering-client.mjs +73 -0
- package/src/engineering-defaults.mjs +17 -0
- package/src/engineering.css +31 -0
- package/src/enterprise-application.mjs +76 -0
- package/src/enterprise-aws-host-infrastructure.mjs +62 -0
- package/src/enterprise-aws-host-tests.mjs +15 -0
- package/src/enterprise-aws-infrastructure-tests.mjs +38 -0
- package/src/enterprise-aws-infrastructure.mjs +138 -0
- package/src/enterprise-google-infrastructure.mjs +84 -0
- package/src/enterprise-google-tests.mjs +25 -0
- package/src/estimate.mjs +188 -0
- package/src/existing-references.mjs +18 -0
- package/src/external-identities.mjs +17 -0
- package/src/faq-lambda-build.mjs +28 -0
- package/src/gcp-structured.mjs +104 -0
- package/src/generation-provider.mjs +7 -0
- package/src/generation-quality.mjs +69 -0
- package/src/handoff.mjs +141 -0
- package/src/ibm-registry.mjs +12 -0
- package/src/ibm-structured.mjs +103 -0
- package/src/identifiers.mjs +15 -0
- package/src/implementation-map.mjs +14 -0
- package/src/implementation-outcome.mjs +8 -0
- package/src/incomplete-terraform.mjs +9 -0
- package/src/integrations.ts +137 -0
- package/src/interface-contracts.mjs +30 -0
- package/src/invoice-application.mjs +66 -0
- package/src/invoice-aws-operations.mjs +136 -0
- package/src/invoice-aws.mjs +143 -0
- package/src/invoice-azure-operations.mjs +147 -0
- package/src/invoice-azure.mjs +134 -0
- package/src/invoice-builder.mjs +35 -0
- package/src/invoice-dependencies.mjs +43 -0
- package/src/invoice-gcp-operations.mjs +178 -0
- package/src/invoice-gcp.mjs +104 -0
- package/src/invoice-ibm-operations.mjs +278 -0
- package/src/invoice-ibm.mjs +142 -0
- package/src/invoice-operations.mjs +143 -0
- package/src/invoice-plan.mjs +45 -0
- package/src/invoice-region.mjs +6 -0
- package/src/invoice-spec-kit.mjs +61 -0
- package/src/invoice-state.mjs +7 -0
- package/src/invoice-terraform.mjs +29 -0
- package/src/invoice-tests.mjs +122 -0
- package/src/journey-workspace.css +72 -0
- package/src/journey.mjs +87 -0
- package/src/levels.mjs +145 -0
- package/src/local-agent.mjs +184 -0
- package/src/main.jsx +2458 -0
- package/src/model-policy-preflight.mjs +34 -0
- package/src/openai-voice.mjs +102 -0
- package/src/output-bundle.mjs +11 -0
- package/src/ownership-inspection.mjs +28 -0
- package/src/pack.mjs +201 -0
- package/src/pricing.mjs +31 -0
- package/src/production-state.mjs +8 -0
- package/src/project-copy.mjs +10 -0
- package/src/project-file.mjs +160 -0
- package/src/project-links.mjs +3 -0
- package/src/protected-state.mjs +43 -0
- package/src/public-faq-builder.mjs +19 -0
- package/src/public-faq-clouds.mjs +251 -0
- package/src/public-faq.mjs +122 -0
- package/src/pulumi.mjs +123 -0
- package/src/python-container.mjs +25 -0
- package/src/python-runtime.mjs +50 -0
- package/src/rag-handler.mjs +43 -0
- package/src/rag-web-assets.mjs +52 -0
- package/src/rag-web.mjs +68 -0
- package/src/records.mjs +177 -0
- package/src/resources.mjs +163 -0
- package/src/review.mjs +252 -0
- package/src/runtime/EnterpriseDocument.java +89 -0
- package/src/runtime/approved_http_destination.py +72 -0
- package/src/runtime/aws-lambda-qualification-lock.json +7 -0
- package/src/runtime/aws-python-lock.json +82 -0
- package/src/runtime/aws-web-python-lock.json +887 -0
- package/src/runtime/aws_json_model.py +42 -0
- package/src/runtime/azure-python-lock.json +863 -0
- package/src/runtime/azure-sources.json +8 -0
- package/src/runtime/azure-test-lock.json +23 -0
- package/src/runtime/azure_acceptance.py +192 -0
- package/src/runtime/azure_structured.py +153 -0
- package/src/runtime/bounded_rag.py +126 -0
- package/src/runtime/catalog_admin.py +70 -0
- package/src/runtime/cloud-sql-proxy-lock.json +8 -0
- package/src/runtime/cloud-sql-proxy-security-review.json +30 -0
- package/src/runtime/connector_cli.py +50 -0
- package/src/runtime/connector_sync.py +70 -0
- package/src/runtime/durable-python-lock.json +247 -0
- package/src/runtime/durable_workflow.py +325 -0
- package/src/runtime/enterprise-application-manifest.json +110 -0
- package/src/runtime/enterprise-application-sources.json +266 -0
- package/src/runtime/enterprise-auth-python-lock.json +592 -0
- package/src/runtime/enterprise-aws-host-bootstrap-source.json +1 -0
- package/src/runtime/enterprise-aws-host-probe-source.json +1 -0
- package/src/runtime/enterprise-aws-task-template.json +235 -0
- package/src/runtime/enterprise-document-lock.json +18 -0
- package/src/runtime/enterprise-document.Dockerfile +15 -0
- package/src/runtime/enterprise-runtime-aws-python-lock.json +1115 -0
- package/src/runtime/enterprise-runtime-azure-python-lock.json +1106 -0
- package/src/runtime/enterprise-runtime-gcp-python-lock.json +1060 -0
- package/src/runtime/enterprise-runtime-ibm-python-lock.json +1096 -0
- package/src/runtime/enterprise-runtime-python-lock.json +1058 -0
- package/src/runtime/enterprise-runtime.Dockerfile +15 -0
- package/src/runtime/enterprise-web-app.js +1 -0
- package/src/runtime/enterprise-web-entry.js +105 -0
- package/src/runtime/enterprise-web-lock.json +29 -0
- package/src/runtime/enterprise-web-notices.txt +229 -0
- package/src/runtime/enterprise-web.css +4 -0
- package/src/runtime/enterprise-web.html +8 -0
- package/src/runtime/enterprise_audit.py +91 -0
- package/src/runtime/enterprise_audit_schema.sql +25 -0
- package/src/runtime/enterprise_auth_schema.sql +67 -0
- package/src/runtime/enterprise_auth_store.py +241 -0
- package/src/runtime/enterprise_aws_host_bootstrap.py +120 -0
- package/src/runtime/enterprise_aws_host_probe.py +105 -0
- package/src/runtime/enterprise_aws_hosts.py +136 -0
- package/src/runtime/enterprise_aws_jobs.py +300 -0
- package/src/runtime/enterprise_aws_objects.py +93 -0
- package/src/runtime/enterprise_aws_transfer.py +83 -0
- package/src/runtime/enterprise_azure_batch_api.py +128 -0
- package/src/runtime/enterprise_azure_host.py +599 -0
- package/src/runtime/enterprise_azure_jobs.py +294 -0
- package/src/runtime/enterprise_azure_objects.py +234 -0
- package/src/runtime/enterprise_azure_pool.py +161 -0
- package/src/runtime/enterprise_azure_transfer.py +122 -0
- package/src/runtime/enterprise_configuration.py +136 -0
- package/src/runtime/enterprise_document.py +116 -0
- package/src/runtime/enterprise_document_cli.py +32 -0
- package/src/runtime/enterprise_document_contract.py +54 -0
- package/src/runtime/enterprise_document_job.py +109 -0
- package/src/runtime/enterprise_document_jobs.py +122 -0
- package/src/runtime/enterprise_document_jobs_schema.sql +23 -0
- package/src/runtime/enterprise_extraction_cache.py +186 -0
- package/src/runtime/enterprise_extraction_schema.sql +17 -0
- package/src/runtime/enterprise_google_jobs.py +275 -0
- package/src/runtime/enterprise_google_transfer.py +85 -0
- package/src/runtime/enterprise_http.py +212 -0
- package/src/runtime/enterprise_identity.py +52 -0
- package/src/runtime/enterprise_knowledge.py +152 -0
- package/src/runtime/enterprise_models.py +94 -0
- package/src/runtime/enterprise_native.py +181 -0
- package/src/runtime/enterprise_oauth.py +132 -0
- package/src/runtime/enterprise_operator.py +160 -0
- package/src/runtime/enterprise_parser_service.py +136 -0
- package/src/runtime/enterprise_parser_transport.py +68 -0
- package/src/runtime/enterprise_queries.py +255 -0
- package/src/runtime/enterprise_queries_schema.sql +27 -0
- package/src/runtime/enterprise_query_service.py +111 -0
- package/src/runtime/enterprise_secrets.py +110 -0
- package/src/runtime/enterprise_sessions.py +95 -0
- package/src/runtime/enterprise_sources.py +260 -0
- package/src/runtime/enterprise_web.py +39 -0
- package/src/runtime/enterprise_worker.py +68 -0
- package/src/runtime/export_contract_acceptance.py +18 -0
- package/src/runtime/faq-output-contract.json +40 -0
- package/src/runtime/faq-web-app.js +41 -0
- package/src/runtime/faq-web.css +1 -0
- package/src/runtime/faq-web.html +6 -0
- package/src/runtime/gcp-sources.json +9 -0
- package/src/runtime/gcp_acceptance.py +110 -0
- package/src/runtime/gcp_structured.py +150 -0
- package/src/runtime/http_acceptance.py +39 -0
- package/src/runtime/iap-web-app.js +36 -0
- package/src/runtime/iap-web-source.json +1 -0
- package/src/runtime/ibm-python-lock.json +856 -0
- package/src/runtime/ibm-sources.json +9 -0
- package/src/runtime/ibm_acceptance.py +133 -0
- package/src/runtime/ibm_structured.py +113 -0
- package/src/runtime/invoice-azapi-provider-lock.json +7 -0
- package/src/runtime/invoice-ibm-provider-lock.json +7 -0
- package/src/runtime/invoice-parser-lock.json +1199 -0
- package/src/runtime/invoice-parser-python-lock.json +56 -0
- package/src/runtime/invoice-parser.Dockerfile +190 -0
- package/src/runtime/invoice-sources.json +58 -0
- package/src/runtime/invoice-test-sources.json +24 -0
- package/src/runtime/invoice-web.css +2 -0
- package/src/runtime/invoice-web.html +12 -0
- package/src/runtime/invoice-web.js +112 -0
- package/src/runtime/invoice_configuration.py +17 -0
- package/src/runtime/invoice_document.py +95 -0
- package/src/runtime/invoice_extraction.py +96 -0
- package/src/runtime/invoice_http.py +129 -0
- package/src/runtime/invoice_identity.py +5 -0
- package/src/runtime/invoice_maintenance.py +40 -0
- package/src/runtime/invoice_native.py +77 -0
- package/src/runtime/invoice_object_store.py +153 -0
- package/src/runtime/invoice_operations.py +108 -0
- package/src/runtime/invoice_operator.py +79 -0
- package/src/runtime/invoice_operator_core.py +39 -0
- package/src/runtime/invoice_operator_job.py +147 -0
- package/src/runtime/invoice_parser_cli.py +17 -0
- package/src/runtime/invoice_parser_identity.py +39 -0
- package/src/runtime/invoice_parser_service.py +89 -0
- package/src/runtime/invoice_parser_transport.py +89 -0
- package/src/runtime/invoice_processing.py +24 -0
- package/src/runtime/invoice_retention.py +16 -0
- package/src/runtime/invoice_runtime_secrets.py +43 -0
- package/src/runtime/invoice_stage.py +80 -0
- package/src/runtime/invoice_web.py +39 -0
- package/src/runtime/invoice_worker.py +50 -0
- package/src/runtime/lambda_faq.py +5 -0
- package/src/runtime/parser-requirements.lock +4 -0
- package/src/runtime/policy_review.py +18 -0
- package/src/runtime/postgres-qualification-lock.json +21 -0
- package/src/runtime/public-faq-sources.json +22 -0
- package/src/runtime/public_catalog_admin.py +122 -0
- package/src/runtime/public_catalog_store.py +125 -0
- package/src/runtime/public_faq.py +144 -0
- package/src/runtime/public_faq_app.py +49 -0
- package/src/runtime/python-container-lock.json +18 -0
- package/src/runtime/rag-sources.json +10 -0
- package/src/runtime/rag_acceptance.py +60 -0
- package/src/runtime/rag_aws_adapter.py +95 -0
- package/src/runtime/rds-ca-source.json +9 -0
- package/src/runtime/rds-global-ca.pem +2888 -0
- package/src/runtime/state-contract-check-source.json +4 -0
- package/src/runtime/state_contract_check.py +338 -0
- package/src/runtime/structured-source.json +1 -0
- package/src/runtime/structured-web-app.js +71 -0
- package/src/runtime/structured-web-source.json +1 -0
- package/src/runtime/structured_http.py +105 -0
- package/src/runtime/structured_output.py +48 -0
- package/src/runtime/web-python-lock.json +802 -0
- package/src/runtime/web_user_admin.py +44 -0
- package/src/runtime/workflow_application.py +62 -0
- package/src/runtime/workflow_bindings.py +128 -0
- package/src/runtime/workflow_configuration.py +40 -0
- package/src/runtime/workflow_connection.py +105 -0
- package/src/runtime/workflow_contract.py +54 -0
- package/src/runtime/workflow_database.py +94 -0
- package/src/runtime/workflow_errors.py +6 -0
- package/src/runtime/workflow_http.py +178 -0
- package/src/runtime/workflow_identity.py +69 -0
- package/src/runtime/workflow_payload.py +118 -0
- package/src/runtime/workflow_process_stage.py +88 -0
- package/src/runtime/workflow_profile.py +91 -0
- package/src/runtime/workflow_review.py +106 -0
- package/src/runtime/workflow_role_bootstrap.py +104 -0
- package/src/runtime/workflow_schema.sql +72 -0
- package/src/runtime/workflow_worker.py +142 -0
- package/src/runtime-settings.mjs +15 -0
- package/src/s3-access.mjs +14 -0
- package/src/source-contracts.mjs +17 -0
- package/src/spec-kit.mjs +186 -0
- package/src/state-custody.mjs +32 -0
- package/src/state-inspection.mjs +45 -0
- package/src/state-spec-kit.mjs +13 -0
- package/src/storage-tests.mjs +25 -0
- package/src/structured-api.mjs +133 -0
- package/src/structured-contract.mjs +19 -0
- package/src/structured-operation-policy.mjs +2 -0
- package/src/structured-web.mjs +17 -0
- package/src/style.css +1 -0
- package/src/system-description.mjs +26 -0
- package/src/terraform-admission.mjs +66 -0
- package/src/terraform-composition.mjs +83 -0
- package/src/terraform-expressions.mjs +46 -0
- package/src/terraform-validation-coverage.mjs +11 -0
- package/src/terraform.mjs +128 -0
- package/src/text-statistics.mjs +51 -0
- package/src/upstream/openarchflow/format-payload.ts +26 -0
- package/src/upstream/openarchflow/import/mermaid.ts +205 -0
- package/src/upstream/openarchflow/import/sql-ddl.ts +109 -0
- package/src/upstream/openarchflow/layout.ts +54 -0
- package/src/upstream/openarchflow/providers/aws.ts +196 -0
- package/src/upstream/openarchflow/providers/azure.ts +126 -0
- package/src/upstream/openarchflow/providers/cloudnative.ts +71 -0
- package/src/upstream/openarchflow/providers/generic.ts +227 -0
- package/src/upstream/openarchflow/providers/integration.ts +22 -0
- package/src/upstream/openarchflow/providers/types.ts +2 -0
- package/src/upstream/openarchflow/templates.ts +937 -0
- package/src/upstream-catalog.mjs +10 -0
- package/src/useChatScroll.jsx +36 -0
- package/src/useEmulation.jsx +36 -0
- package/src/validation-receipt.mjs +10 -0
- package/src/visual-export.mjs +92 -0
- package/src/voice-conversation.mjs +117 -0
- package/src/work-intake.mjs +24 -0
- package/src/workflow-runtime-inventory.mjs +3 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"""Codex adapter for portable engineering sessions; no public/browser endpoint.
|
|
2
|
+
|
|
3
|
+
Workspace registrations and scope originate from the worker's trusted control plane.
|
|
4
|
+
The native sandbox constrains writes/network, but this adapter alone is NOT a hosted
|
|
5
|
+
multi-tenant isolation boundary. Hosted workers need separately qualified isolation.
|
|
6
|
+
"""
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from .codex_app_server import CodexAppServer, ProtocolError
|
|
9
|
+
from .engineering_sessions import BackendEvent, EmptySessionUnavailable, RecoveredStart, SessionError
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CodexEngineeringBackend:
|
|
13
|
+
name='codex-app-server'
|
|
14
|
+
|
|
15
|
+
def __init__(self,workspaces,*,client_factory=CodexAppServer,instructions='',permission_profile=None,tools=None):
|
|
16
|
+
self.workspaces=dict(workspaces)
|
|
17
|
+
self.client_factory=client_factory
|
|
18
|
+
self.instructions=instructions
|
|
19
|
+
self.permission_profile=permission_profile
|
|
20
|
+
self.tools=tools
|
|
21
|
+
if permission_profile:
|
|
22
|
+
# The durable coordinator must refuse a legacy-policy fallback after
|
|
23
|
+
# restart, even though both implementations use the same model API.
|
|
24
|
+
self.name=f'codex-app-server:{permission_profile}'
|
|
25
|
+
self.clients={}
|
|
26
|
+
|
|
27
|
+
def _workspace(self,scope,workspace):
|
|
28
|
+
registered=self.workspaces.get((scope,workspace))
|
|
29
|
+
if registered is None:
|
|
30
|
+
raise SessionError('Workspace is not registered for this project')
|
|
31
|
+
root=Path(registered).resolve(strict=True)
|
|
32
|
+
if not root.is_dir():
|
|
33
|
+
raise SessionError('Registered workspace is unavailable')
|
|
34
|
+
return root
|
|
35
|
+
|
|
36
|
+
@staticmethod
|
|
37
|
+
def _policy(root):
|
|
38
|
+
return {'type':'workspaceWrite','writableRoots':[str(root)],'networkAccess':False,
|
|
39
|
+
'excludeSlashTmp':True,'excludeTmpdirEnvVar':True}
|
|
40
|
+
|
|
41
|
+
def _verify(self,result,root,selection):
|
|
42
|
+
policy=result.get('sandbox',{})
|
|
43
|
+
if result.get('cwd')!=str(root) or result.get('model')!=selection.model or result.get('reasoningEffort')!=selection.effort:
|
|
44
|
+
raise SessionError('Codex did not confirm the selected workspace, model and reasoning effort')
|
|
45
|
+
expected_network=bool(self.permission_profile)
|
|
46
|
+
if result.get('approvalPolicy')!='never' or policy.get('type')!='workspaceWrite' or policy.get('networkAccess') is not expected_network:
|
|
47
|
+
raise SessionError('Codex did not confirm the required local execution policy')
|
|
48
|
+
if policy.get('excludeSlashTmp') is not True or policy.get('excludeTmpdirEnvVar') is not True or set(policy.get('writableRoots',[]))-{str(root)}:
|
|
49
|
+
raise SessionError('Codex returned additional writable roots or temporary directories')
|
|
50
|
+
if self.permission_profile:
|
|
51
|
+
if result.get('activePermissionProfile',{}).get('id')!=self.permission_profile or result.get('runtimeWorkspaceRoots')!=[str(root)]:
|
|
52
|
+
raise SessionError('Codex did not confirm the selected worker profile and sole project root')
|
|
53
|
+
sources=result.get('instructionSources',[])
|
|
54
|
+
if not isinstance(sources,list) or any(not isinstance(source,str) or not Path(source).resolve().is_relative_to(root) for source in sources):
|
|
55
|
+
raise SessionError('The native worker inherited instructions outside this project workspace')
|
|
56
|
+
handle=result.get('thread',{}).get('id')
|
|
57
|
+
if not isinstance(handle,str) or not handle:
|
|
58
|
+
raise SessionError('Codex did not confirm a thread')
|
|
59
|
+
return handle
|
|
60
|
+
|
|
61
|
+
def _params(self,root,selection):
|
|
62
|
+
return {'cwd':str(root),'model':selection.model,'approvalPolicy':'never',
|
|
63
|
+
**({'permissions':self.permission_profile,'config':{'model_reasoning_effort':selection.effort}}
|
|
64
|
+
if self.permission_profile else {'sandbox':'workspace-write','config':{
|
|
65
|
+
'model_reasoning_effort':selection.effort,
|
|
66
|
+
'sandbox_workspace_write.network_access':False,
|
|
67
|
+
'sandbox_workspace_write.exclude_slash_tmp':True,
|
|
68
|
+
'sandbox_workspace_write.exclude_tmpdir_env_var':True}}),
|
|
69
|
+
**({'developerInstructions':self.instructions} if self.instructions else {})}
|
|
70
|
+
|
|
71
|
+
def _owned(self,scope,handle,selection=None):
|
|
72
|
+
row=self.clients.get((scope,handle))
|
|
73
|
+
if not row or (selection is not None and row[2]!=selection):
|
|
74
|
+
raise SessionError('Codex session is unavailable for this project or model selection')
|
|
75
|
+
return row
|
|
76
|
+
|
|
77
|
+
def _bind_tools(self,client,scope,workspace,handle):
|
|
78
|
+
if self.tools is None:return
|
|
79
|
+
async def invoke(params):
|
|
80
|
+
self._owned(scope,handle)
|
|
81
|
+
if not isinstance(params,dict) or set(params)-{'threadId','turnId','callId','tool','arguments','namespace'} or params.get('threadId')!=handle or params.get('namespace') is not None:
|
|
82
|
+
raise SessionError('Native tool callback belongs to another thread or namespace')
|
|
83
|
+
return await self.tools.invoke(scope,workspace,params.get('turnId'),params.get('callId'),params.get('tool'),params.get('arguments'))
|
|
84
|
+
client.dynamic_tool_handler=invoke
|
|
85
|
+
|
|
86
|
+
async def create(self,scope,workspace,selection):
|
|
87
|
+
root=self._workspace(scope,workspace)
|
|
88
|
+
client=self.client_factory(root)
|
|
89
|
+
try:
|
|
90
|
+
if self.tools is not None:client.experimental=True
|
|
91
|
+
await client.start()
|
|
92
|
+
result=await client.request('thread/start',{**self._params(root,selection),
|
|
93
|
+
**({'dynamicTools':self.tools.specs} if self.tools is not None else {})})
|
|
94
|
+
handle=self._verify(result,root,selection)
|
|
95
|
+
if self.permission_profile:
|
|
96
|
+
await client.verify_worker_tools(self.permission_profile)
|
|
97
|
+
if (scope,handle) in self.clients:
|
|
98
|
+
raise SessionError('Codex returned a previously registered thread')
|
|
99
|
+
self.clients[scope,handle]=(client,root,selection)
|
|
100
|
+
self._bind_tools(client,scope,workspace,handle)
|
|
101
|
+
return handle
|
|
102
|
+
except BaseException:
|
|
103
|
+
await client.close();raise
|
|
104
|
+
|
|
105
|
+
async def resume(self,scope,handle,workspace,selection):
|
|
106
|
+
root=self._workspace(scope,workspace)
|
|
107
|
+
if (scope,handle) in self.clients:
|
|
108
|
+
row=self._owned(scope,handle,selection)
|
|
109
|
+
if row[1]!=root:
|
|
110
|
+
raise SessionError('A session cannot change its registered workspace')
|
|
111
|
+
client=row[0]
|
|
112
|
+
process=getattr(client,'process',None)
|
|
113
|
+
if not getattr(client,'failure',None) and (process is None or process.returncode is None):
|
|
114
|
+
return
|
|
115
|
+
# A dead cached transport cannot recover itself. Reopen the same
|
|
116
|
+
# persisted native thread; never start a replacement for accepted work.
|
|
117
|
+
self.clients.pop((scope,handle))
|
|
118
|
+
await client.close()
|
|
119
|
+
client=self.client_factory(root)
|
|
120
|
+
try:
|
|
121
|
+
if self.tools is not None:client.experimental=True
|
|
122
|
+
await client.start()
|
|
123
|
+
# App-server resume reloads runtime configuration. Reassert the exact
|
|
124
|
+
# project model/effort and execution policy instead of inheriting the
|
|
125
|
+
# worker's current defaults, then verify its acknowledgement below.
|
|
126
|
+
params=self._params(root,selection)
|
|
127
|
+
result=await client.request('thread/resume',{
|
|
128
|
+
**params,'threadId':handle,'excludeTurns':True})
|
|
129
|
+
if self._verify(result,root,selection)!=handle:
|
|
130
|
+
raise SessionError('Codex resumed a different thread')
|
|
131
|
+
if self.permission_profile:
|
|
132
|
+
await client.verify_worker_tools(self.permission_profile)
|
|
133
|
+
self.clients[scope,handle]=(client,root,selection)
|
|
134
|
+
self._bind_tools(client,scope,workspace,handle)
|
|
135
|
+
except ProtocolError as error:
|
|
136
|
+
await client.close()
|
|
137
|
+
if error.category=='missing_thread':
|
|
138
|
+
raise EmptySessionUnavailable('Native thread has no stored history') from None
|
|
139
|
+
raise
|
|
140
|
+
except BaseException:
|
|
141
|
+
await client.close();raise
|
|
142
|
+
|
|
143
|
+
async def start(self,scope,handle,text,selection,*,request_id=None,context=None):
|
|
144
|
+
client,root,_=self._owned(scope,handle,selection)
|
|
145
|
+
inputs = self._inputs(scope, text, context)
|
|
146
|
+
result=await client.request('turn/start',{'threadId':handle,
|
|
147
|
+
'input':inputs,'cwd':str(root),
|
|
148
|
+
'model':selection.model,'effort':selection.effort,
|
|
149
|
+
'approvalPolicy':'never',
|
|
150
|
+
**({'permissions':self.permission_profile} if self.permission_profile else {'sandboxPolicy':self._policy(root)}),
|
|
151
|
+
**({'clientUserMessageId':request_id} if request_id is not None else {})})
|
|
152
|
+
turn=result.get('turn',{})
|
|
153
|
+
if turn.get('status')!='inProgress' or not isinstance(turn.get('id'),str) or not turn['id']:
|
|
154
|
+
raise SessionError('Codex did not confirm an active engineering turn')
|
|
155
|
+
return turn['id']
|
|
156
|
+
|
|
157
|
+
async def recover_start(self,scope,handle,request_id):
|
|
158
|
+
"""Match durable client message identity; never infer acceptance from text.
|
|
159
|
+
|
|
160
|
+
This is acknowledgement recovery, not an idempotent resubmission promise.
|
|
161
|
+
An absent/ambiguous match leaves the reservation unresolved.
|
|
162
|
+
"""
|
|
163
|
+
client,_,_=self._owned(scope,handle)
|
|
164
|
+
cursor=None;seen=set();matches=[]
|
|
165
|
+
for _ in range(20):
|
|
166
|
+
params={'threadId':handle,'limit':100,'sortDirection':'desc','itemsView':'summary'}
|
|
167
|
+
if cursor is not None:params['cursor']=cursor
|
|
168
|
+
result=await client.request('thread/turns/list',params)
|
|
169
|
+
turns=result.get('data')
|
|
170
|
+
if not isinstance(turns,list):raise SessionError('Native start history is unavailable')
|
|
171
|
+
for candidate in turns:
|
|
172
|
+
if not isinstance(candidate,dict) or not isinstance(candidate.get('items'),list):
|
|
173
|
+
raise SessionError('Native start history is malformed')
|
|
174
|
+
for item in candidate['items']:
|
|
175
|
+
if not isinstance(item,dict):raise SessionError('Native message identity is malformed')
|
|
176
|
+
if item.get('type')=='userMessage' and item.get('clientId')==request_id:
|
|
177
|
+
status=candidate.get('status')
|
|
178
|
+
matches.append(RecoveredStart(request_id,candidate.get('id'),'running' if status=='inProgress' else status))
|
|
179
|
+
cursor=result.get('nextCursor')
|
|
180
|
+
if cursor is None:
|
|
181
|
+
if len(matches)>1:raise SessionError('Native start identity is ambiguous; no work was replayed')
|
|
182
|
+
return matches[0] if matches else None
|
|
183
|
+
if not isinstance(cursor,str) or not cursor or cursor in seen:
|
|
184
|
+
raise SessionError('Native start history cursor is invalid')
|
|
185
|
+
seen.add(cursor)
|
|
186
|
+
raise SessionError('Native start history exceeded the recovery bound')
|
|
187
|
+
|
|
188
|
+
async def observe(self,scope,handle,turn):
|
|
189
|
+
"""Recover terminal state without resubmitting work or loading its content.
|
|
190
|
+
|
|
191
|
+
Missing, malformed or excessively paginated history is uncertain, never
|
|
192
|
+
an idle session. The control-plane reservation remains in place.
|
|
193
|
+
"""
|
|
194
|
+
client,_,_=self._owned(scope,handle)
|
|
195
|
+
cursor=None
|
|
196
|
+
seen=set()
|
|
197
|
+
for _ in range(20):
|
|
198
|
+
params={'threadId':handle,'limit':100,'sortDirection':'desc','itemsView':'notLoaded'}
|
|
199
|
+
if cursor is not None:
|
|
200
|
+
params['cursor']=cursor
|
|
201
|
+
result=await client.request('thread/turns/list',params)
|
|
202
|
+
turns=result.get('data')
|
|
203
|
+
if not isinstance(turns,list):
|
|
204
|
+
raise SessionError('Codex turn history is unavailable; recovery is required')
|
|
205
|
+
for candidate in turns:
|
|
206
|
+
if not isinstance(candidate,dict):
|
|
207
|
+
raise SessionError('Codex returned malformed turn history')
|
|
208
|
+
if candidate.get('id')==turn:
|
|
209
|
+
status=candidate.get('status')
|
|
210
|
+
if status=='inProgress':
|
|
211
|
+
return None
|
|
212
|
+
if status in {'completed','failed','interrupted'}:
|
|
213
|
+
return BackendEvent(turn,status)
|
|
214
|
+
raise SessionError('Codex returned an unknown recovered turn status')
|
|
215
|
+
cursor=result.get('nextCursor')
|
|
216
|
+
if cursor is None:
|
|
217
|
+
break
|
|
218
|
+
if not isinstance(cursor,str) or not cursor or cursor in seen:
|
|
219
|
+
raise SessionError('Codex returned an invalid turn-history cursor')
|
|
220
|
+
seen.add(cursor)
|
|
221
|
+
raise SessionError('The owned turn was not found in bounded history; recovery is required')
|
|
222
|
+
|
|
223
|
+
@staticmethod
|
|
224
|
+
def _inputs(scope, text, context):
|
|
225
|
+
inputs = [{'type':'text','text':text}]
|
|
226
|
+
if context is not None:
|
|
227
|
+
from .engineering_contexts import context_input
|
|
228
|
+
if context.get('projectId') != scope.project:
|
|
229
|
+
raise SessionError('Project context does not belong to this engineering session')
|
|
230
|
+
inputs.append(context_input(context))
|
|
231
|
+
return inputs
|
|
232
|
+
|
|
233
|
+
async def steer(self,scope,handle,turn,text,*,request_id=None,context=None):
|
|
234
|
+
client,_,_=self._owned(scope,handle)
|
|
235
|
+
await client.request('turn/steer',{'threadId':handle,'expectedTurnId':turn,
|
|
236
|
+
'input':self._inputs(scope, text, context),
|
|
237
|
+
**({'clientUserMessageId':request_id} if request_id is not None else {})})
|
|
238
|
+
|
|
239
|
+
async def interrupt(self,scope,handle,turn):
|
|
240
|
+
client,_,_=self._owned(scope,handle)
|
|
241
|
+
await client.request('turn/interrupt',{'threadId':handle,'turnId':turn})
|
|
242
|
+
|
|
243
|
+
async def next_event(self,scope,handle):
|
|
244
|
+
client,_,_=self._owned(scope,handle)
|
|
245
|
+
while True:
|
|
246
|
+
message=await client.notification()
|
|
247
|
+
method=message.get('method');params=message.get('params',{})
|
|
248
|
+
if params.get('threadId') not in (None,handle):
|
|
249
|
+
raise SessionError('Codex notification belongs to another thread')
|
|
250
|
+
if method=='turn/completed':
|
|
251
|
+
turn=params.get('turn',{});status=turn.get('status')
|
|
252
|
+
if status not in {'completed','failed','interrupted'}:
|
|
253
|
+
raise SessionError('Codex returned an unknown terminal turn status')
|
|
254
|
+
return BackendEvent(turn.get('id'),status)
|
|
255
|
+
if method=='item/agentMessage/delta':
|
|
256
|
+
return BackendEvent(params.get('turnId'),'message',params.get('delta',''))
|
|
257
|
+
if method in {'item/started','item/completed'}:
|
|
258
|
+
item=params.get('item',{})
|
|
259
|
+
if params.get('turnId'):
|
|
260
|
+
# Tool summaries are progress, never successful validation.
|
|
261
|
+
return BackendEvent(params['turnId'],'progress',str(item.get('type','work')))
|
|
262
|
+
|
|
263
|
+
async def close(self):
|
|
264
|
+
rows=list(self.clients.values());self.clients.clear()
|
|
265
|
+
for client,_,_ in rows:
|
|
266
|
+
await client.close()
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"""Trusted local worker policy, separate from browser input and model selection.
|
|
2
|
+
|
|
3
|
+
This constrains native local commands, not a hosted OS/tenant boundary. Only
|
|
4
|
+
control-plane selected tool directories may be added as read roots. Do not pass
|
|
5
|
+
client paths, source repositories or credential directories here.
|
|
6
|
+
"""
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
import re
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
import shutil
|
|
12
|
+
import tomllib
|
|
13
|
+
|
|
14
|
+
from .codex_app_server import CodexAppServer
|
|
15
|
+
|
|
16
|
+
PROFILE = 'atmem-engineering-v2'
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def configured_mcp_names():
|
|
20
|
+
"""Inspect names only; never copy credentials or server definitions.
|
|
21
|
+
|
|
22
|
+
An empty table override merges with the user's existing table in current
|
|
23
|
+
Codex versions. Explicitly disable known entries; the live worker check must
|
|
24
|
+
still reject any server introduced by another effective configuration layer.
|
|
25
|
+
"""
|
|
26
|
+
names=set()
|
|
27
|
+
paths=[Path('/etc/codex/config.toml'),Path(os.getenv('CODEX_HOME',str(Path.home()/'.codex')))/'config.toml']
|
|
28
|
+
def collect(value):
|
|
29
|
+
if not isinstance(value,dict):return
|
|
30
|
+
servers=value.get('mcp_servers',{})
|
|
31
|
+
if isinstance(servers,dict):names.update(servers)
|
|
32
|
+
for nested in value.values():
|
|
33
|
+
if isinstance(nested,dict):collect(nested)
|
|
34
|
+
for path in paths:
|
|
35
|
+
if path.exists():
|
|
36
|
+
with path.open('rb') as source:collect(tomllib.load(source))
|
|
37
|
+
return sorted(names)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def configured_shell_override_names():
|
|
41
|
+
"""Return keys to blank in the worker; never forward their original values."""
|
|
42
|
+
names=set()
|
|
43
|
+
paths=[Path('/etc/codex/config.toml'),Path(os.getenv('CODEX_HOME',str(Path.home()/'.codex')))/'config.toml']
|
|
44
|
+
def collect(value):
|
|
45
|
+
if not isinstance(value,dict):return
|
|
46
|
+
policy=value.get('shell_environment_policy',{})
|
|
47
|
+
if isinstance(policy,dict) and isinstance(policy.get('set',{}),dict):names.update(policy.get('set',{}))
|
|
48
|
+
for nested in value.values():
|
|
49
|
+
if isinstance(nested,dict):collect(nested)
|
|
50
|
+
for path in paths:
|
|
51
|
+
if path.exists():
|
|
52
|
+
with path.open('rb') as source:collect(tomllib.load(source))
|
|
53
|
+
return sorted(names)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def worker_command(read_roots=(),*,temporary_dir=None):
|
|
57
|
+
executable = shutil.which('codex')
|
|
58
|
+
if not executable:
|
|
59
|
+
raise RuntimeError('The selected native worker is unavailable')
|
|
60
|
+
binary = Path(executable).resolve(strict=True)
|
|
61
|
+
# Include the symlink's directory and native package tree so the CLI's
|
|
62
|
+
# sandbox helper can execute. These are code paths, not its auth/state home.
|
|
63
|
+
roots = {Path(executable).parent.resolve(), binary.parent}
|
|
64
|
+
for root in read_roots:
|
|
65
|
+
path = Path(root).resolve(strict=True)
|
|
66
|
+
if not path.is_dir():
|
|
67
|
+
raise ValueError('A worker tool read root must be an existing directory')
|
|
68
|
+
secrets = [Path.home()/name for name in ['.codex','.aws','.ssh','.kube']]
|
|
69
|
+
if Path.home().is_relative_to(path) or any(path.is_relative_to(p) or p.is_relative_to(path) for p in secrets):
|
|
70
|
+
raise ValueError('Worker tools cannot expose a home or credential tree')
|
|
71
|
+
roots.add(path)
|
|
72
|
+
forbidden = {Path('/'), Path.home(), Path.home()/'.codex', Path.home()/'.aws', Path.home()/'.ssh'}
|
|
73
|
+
if roots & forbidden:
|
|
74
|
+
raise ValueError('Worker tool roots cannot grant filesystem, home or credential trees')
|
|
75
|
+
entries = {':root':'deny', ':minimal':'read', ':tmpdir':'deny', ':slash_tmp':'deny'}
|
|
76
|
+
entries.update({str(p):'read' for p in sorted(roots)})
|
|
77
|
+
filesystem = ','.join(f'{json.dumps(k)}={json.dumps(v)}' for k,v in entries.items())
|
|
78
|
+
# The native proxy must be active to propagate its Unix-socket allowlist.
|
|
79
|
+
# No domain is allowed, local binding is forbidden and raw IP access remains
|
|
80
|
+
# sandboxed. The profile's enabled flag is not an unrestricted network grant.
|
|
81
|
+
network='enabled=true,domains={},proxy_url="http://127.0.0.1:0",enable_socks5=false,allow_local_binding=false'
|
|
82
|
+
if temporary_dir is not None:
|
|
83
|
+
# Terraform's provider protocol binds random AF_UNIX sockets beneath its
|
|
84
|
+
# private temp directory. Permit only that subtree, never Docker/host IPC
|
|
85
|
+
# or IP networking. This must be requalified per native worker platform.
|
|
86
|
+
network+=',unix_sockets={'+json.dumps(str(temporary_dir))+'="allow"}'
|
|
87
|
+
definition = f'permissions.{PROFILE}={{extends=":workspace",filesystem={{{filesystem}}},network={{{network}}}}}'
|
|
88
|
+
command = [str(binary),'app-server','--listen','stdio://',
|
|
89
|
+
'-c','analytics.enabled=false','-c',definition,
|
|
90
|
+
'-c',f'default_permissions={json.dumps(PROFILE)}',
|
|
91
|
+
'-c','shell_environment_policy.inherit="core"',
|
|
92
|
+
'-c','shell_environment_policy.ignore_default_excludes=false',
|
|
93
|
+
'-c','allow_login_shell=false','-c','features.shell_snapshot=false',
|
|
94
|
+
'-c','features.network_proxy=true',
|
|
95
|
+
'-c','mcp_servers={}','-c','features.apps=false','-c','features.plugins=false',
|
|
96
|
+
'-c','web_search="disabled"']
|
|
97
|
+
if temporary_dir is not None:
|
|
98
|
+
command.extend(['-c',f'shell_environment_policy.set.TMPDIR={json.dumps(str(temporary_dir))}'])
|
|
99
|
+
for name in configured_mcp_names():
|
|
100
|
+
# CLI override dotted paths do not parse TOML quotes in key segments.
|
|
101
|
+
# Refuse unusual keys rather than creating a second, ineffective entry.
|
|
102
|
+
if not re.fullmatch(r'[A-Za-z0-9_-]+',name):
|
|
103
|
+
raise ValueError('An MCP configuration key cannot be disabled safely by this worker')
|
|
104
|
+
command.extend(['-c',f'mcp_servers.{name}.enabled=false'])
|
|
105
|
+
for name in configured_shell_override_names():
|
|
106
|
+
if name=='TMPDIR':continue
|
|
107
|
+
if not re.fullmatch(r'[A-Za-z_][A-Za-z0-9_]*',name):
|
|
108
|
+
raise ValueError('A shell override key cannot be disabled safely by this worker')
|
|
109
|
+
command.extend(['-c',f'shell_environment_policy.set.{name}=""'])
|
|
110
|
+
return command
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class CodexWorkerClient(CodexAppServer):
|
|
114
|
+
def __init__(self,workspace,*,read_roots=()):
|
|
115
|
+
root=Path(workspace).resolve(strict=True)
|
|
116
|
+
temporary=root/'.worker-tmp'
|
|
117
|
+
if os.name=='posix' and len(os.fsencode(temporary))>80:
|
|
118
|
+
raise ValueError('Register a shorter worker workspace path for Unix-socket validators')
|
|
119
|
+
if temporary.is_symlink():
|
|
120
|
+
raise ValueError('Worker temporary storage cannot be a symlink')
|
|
121
|
+
temporary.mkdir(exist_ok=True)
|
|
122
|
+
command=worker_command(read_roots,temporary_dir=temporary)
|
|
123
|
+
definition=next(value for value in command if value.startswith(f'permissions.{PROFILE}='))
|
|
124
|
+
self.expected_worker_profile=tomllib.loads(definition)['permissions'][PROFILE]
|
|
125
|
+
super().__init__(root,command=command,experimental=True)
|
|
126
|
+
|
|
127
|
+
async def verify_worker_tools(self,expected_profile=PROFILE):
|
|
128
|
+
if expected_profile!=PROFILE:
|
|
129
|
+
raise RuntimeError('This worker cannot attest a different named permission profile')
|
|
130
|
+
effective=await self.request('config/read',{'includeLayers':False,'cwd':str(self.workspace)})
|
|
131
|
+
config=effective.get('config')
|
|
132
|
+
if not isinstance(config,dict):
|
|
133
|
+
raise RuntimeError('Worker configuration acknowledgement is unavailable')
|
|
134
|
+
definitions=config.get('mcp_servers',{})
|
|
135
|
+
if not isinstance(definitions,dict) or any(not isinstance(v,dict) or v.get('enabled') is not False for v in definitions.values()):
|
|
136
|
+
raise RuntimeError('Unapproved MCP enablement is present in this local worker')
|
|
137
|
+
features=config.get('features',{})
|
|
138
|
+
if not isinstance(features,dict) or features.get('apps') is not False or features.get('plugins') is not False or config.get('web_search')!='disabled':
|
|
139
|
+
raise RuntimeError('External tools were not disabled in this local worker')
|
|
140
|
+
shell=config.get('shell_environment_policy',{})
|
|
141
|
+
if config.get('allow_login_shell') is not False or features.get('shell_snapshot') is not False or not isinstance(shell,dict) or shell.get('inherit')!='core' or shell.get('ignore_default_excludes') is not False or shell.get('include_only') not in (None,[]):
|
|
142
|
+
raise RuntimeError('The restricted worker shell environment was not confirmed')
|
|
143
|
+
overrides=shell.get('set')
|
|
144
|
+
if not isinstance(overrides,dict) or overrides.get('TMPDIR')!=str(self.workspace/'.worker-tmp') or any(k!='TMPDIR' and v!='' for k,v in overrides.items()):
|
|
145
|
+
raise RuntimeError('Unexpected inherited shell variable overrides were configured')
|
|
146
|
+
profile=config.get('permissions',{}).get(PROFILE,{})
|
|
147
|
+
network=profile.get('network',{})
|
|
148
|
+
if features.get('network_proxy') is not True or network.get('enabled') is not True or network.get('domains') not in ({},None) or network.get('allow_local_binding') is not False:
|
|
149
|
+
raise RuntimeError('The deny-all worker proxy was not confirmed')
|
|
150
|
+
filesystem=profile.get('filesystem')
|
|
151
|
+
if isinstance(filesystem,dict):
|
|
152
|
+
filesystem=dict(filesystem)
|
|
153
|
+
if filesystem.get('glob_scan_max_depth') is None:filesystem.pop('glob_scan_max_depth',None)
|
|
154
|
+
if profile.get('extends')!=':workspace' or filesystem!=self.expected_worker_profile['filesystem']:
|
|
155
|
+
raise RuntimeError('The worker filesystem policy changed in an effective configuration layer')
|
|
156
|
+
if network.get('unix_sockets')!=self.expected_worker_profile['network'].get('unix_sockets') or network.get('dangerously_allow_all_unix_sockets') is True or network.get('dangerously_allow_non_loopback_proxy') is True:
|
|
157
|
+
raise RuntimeError('Unexpected local socket access was added to the worker')
|
|
158
|
+
roots=profile.get('workspace_roots',{}) or {}
|
|
159
|
+
if not isinstance(roots,dict) or any(value is not False for value in roots.values()):
|
|
160
|
+
raise RuntimeError('Unexpected profile-owned workspace roots were added')
|
|
161
|
+
result=await self.request('mcpServerStatus/list',{'limit':100})
|
|
162
|
+
states=result.get('data')
|
|
163
|
+
if not isinstance(states,list) or result.get('nextCursor'):
|
|
164
|
+
raise RuntimeError('Unapproved MCP tools are configured in this local worker')
|
|
165
|
+
# The status API lists disabled definitions too. Require both effective
|
|
166
|
+
# disabled configuration and no initialized server/tool/resource surface.
|
|
167
|
+
for state in states:
|
|
168
|
+
if not isinstance(state,dict) or state.get('name') not in definitions or state.get('runtimeStatus') is not None or state.get('tools')!={} or state.get('resources')!=[] or state.get('resourceTemplates')!=[]:
|
|
169
|
+
raise RuntimeError('An MCP server exposed tools or resources in this local worker')
|
|
170
|
+
return {'configuredMcpDefinitions':len(definitions),'allDisabled':True,'exposedMcpTools':0,'apps':False,'plugins':False,'webSearch':'disabled'}
|