@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,67 @@
|
|
|
1
|
+
"""Project-scoped public activity, never model reasoning or raw protocol output."""
|
|
2
|
+
from datetime import datetime,timezone
|
|
3
|
+
import json
|
|
4
|
+
import re
|
|
5
|
+
import sqlite3
|
|
6
|
+
import uuid
|
|
7
|
+
|
|
8
|
+
KINDS={'context_started','context_ready','pass_started','model_started','model_message','model_checked','response_repair','tool_started','tool_finished','tool_cached','response_ready','failed','cancelled'}
|
|
9
|
+
DETAILS={'round','attempt','provider','model','effort','skillIds','recordCount','knowledgeCount','tool','success','cached','encoding','proposal','requirementCount','decisionCount'}
|
|
10
|
+
|
|
11
|
+
def now():return datetime.now(timezone.utc).isoformat()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ArchitectureActivity:
|
|
15
|
+
def __init__(self,path):
|
|
16
|
+
self.db=sqlite3.connect(path);self.db.row_factory=sqlite3.Row
|
|
17
|
+
self.db.execute('''CREATE TABLE IF NOT EXISTS architecture_turns (
|
|
18
|
+
id TEXT PRIMARY KEY, project TEXT NOT NULL, metadata TEXT NOT NULL,
|
|
19
|
+
state TEXT NOT NULL, started TEXT NOT NULL)''')
|
|
20
|
+
self.db.execute('''CREATE TABLE IF NOT EXISTS architecture_events (
|
|
21
|
+
sequence INTEGER PRIMARY KEY AUTOINCREMENT, turn TEXT NOT NULL,
|
|
22
|
+
payload TEXT NOT NULL)''')
|
|
23
|
+
with self.db:self.db.execute("UPDATE architecture_turns SET state='recovery_required' WHERE state='running'")
|
|
24
|
+
|
|
25
|
+
def close(self):self.db.close()
|
|
26
|
+
|
|
27
|
+
def owned(self,project,turn):
|
|
28
|
+
row=self.db.execute('SELECT * FROM architecture_turns WHERE id=? AND project=?',(turn,project)).fetchone()
|
|
29
|
+
if row is None:raise LookupError('Architecture activity is unavailable for this project')
|
|
30
|
+
return row
|
|
31
|
+
|
|
32
|
+
def start(self,project,turn,metadata):
|
|
33
|
+
if not isinstance(project,str) or not re.fullmatch(r'[A-Za-z0-9-]{8,64}',project) or not isinstance(turn,str) or str(uuid.UUID(turn))!=turn:
|
|
34
|
+
raise ValueError('Use an exact project and canonical activity UUID')
|
|
35
|
+
if set(metadata)-{'provider','model','effort','origin','revision'}:raise ValueError('Unsupported public turn metadata')
|
|
36
|
+
if self.db.execute('SELECT 1 FROM architecture_turns WHERE id=?',(turn,)).fetchone():
|
|
37
|
+
raise ValueError('This architecture request is already recorded; it was not replayed')
|
|
38
|
+
if self.db.execute('SELECT COUNT(*) FROM architecture_turns WHERE project=?',(project,)).fetchone()[0]>=1000:
|
|
39
|
+
raise ValueError('Architecture activity reached its history bound; no earlier turn was removed')
|
|
40
|
+
with self.db:self.db.execute('INSERT INTO architecture_turns VALUES (?,?,?,?,?)',(turn,project,json.dumps(metadata,allow_nan=False),'running',now()))
|
|
41
|
+
|
|
42
|
+
def append(self,project,turn,event):
|
|
43
|
+
row=self.owned(project,turn)
|
|
44
|
+
if row['state']!='running':raise ValueError('Activity is already settled; no work was replayed')
|
|
45
|
+
if set(event)-{'kind','text','details'} or event.get('kind') not in KINDS or not isinstance(event.get('text'),str) or len(event['text'])>16000:
|
|
46
|
+
raise ValueError('Unsupported public activity event')
|
|
47
|
+
details=event.get('details',{})
|
|
48
|
+
if not isinstance(details,dict) or set(details)-DETAILS:raise ValueError('Private or unsupported activity details are forbidden')
|
|
49
|
+
for value in details.values():
|
|
50
|
+
if value is not None and type(value) not in {str,int,bool,list}:raise ValueError('Unsupported activity detail')
|
|
51
|
+
if isinstance(value,list) and (len(value)>100 or any(not isinstance(v,str) or len(v)>200 for v in value)):raise ValueError('Invalid public activity references')
|
|
52
|
+
if self.db.execute('SELECT COUNT(*) FROM architecture_events WHERE turn=?',(turn,)).fetchone()[0]>=500:raise ValueError('Activity event bound reached; no events were discarded')
|
|
53
|
+
encoded=json.dumps({**event,'at':now()},ensure_ascii=False,allow_nan=False)
|
|
54
|
+
if len(encoded.encode())>80000:raise ValueError('Activity event is oversized; no text was clipped')
|
|
55
|
+
with self.db:self.db.execute('INSERT INTO architecture_events(turn,payload) VALUES (?,?)',(turn,encoded))
|
|
56
|
+
|
|
57
|
+
def finish(self,project,turn,state):
|
|
58
|
+
if state not in {'response_ready','failed','cancelled','details_unavailable'}:raise ValueError('Unsupported activity state')
|
|
59
|
+
self.owned(project,turn)
|
|
60
|
+
with self.db:self.db.execute("UPDATE architecture_turns SET state=? WHERE id=? AND project=? AND state='running'",(state,turn,project))
|
|
61
|
+
|
|
62
|
+
def read(self,project,turn,after=0):
|
|
63
|
+
row=self.owned(project,turn)
|
|
64
|
+
if type(after) is not int or after<0:raise ValueError('Invalid activity cursor')
|
|
65
|
+
events=[{'sequence':r['sequence'],**json.loads(r['payload'])} for r in self.db.execute('SELECT sequence,payload FROM architecture_events WHERE turn=? AND sequence>? ORDER BY sequence LIMIT 200',(turn,after))]
|
|
66
|
+
return {'id':turn,'projectId':project,'state':row['state'],'startedAt':row['started'],'selection':json.loads(row['metadata']),'events':events,
|
|
67
|
+
'boundary':'Recorded public model messages and observed host actions. No private reasoning, raw prompts, credentials or provider protocol dumps. Response readiness is not design/application acceptance.'}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Bounded, ephemeral attachment parsing. Content is evidence, never instructions."""
|
|
2
|
+
import base64,io,json,subprocess,sys,zipfile,zlib
|
|
3
|
+
from urllib.parse import unquote_to_bytes
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from xml.etree import ElementTree
|
|
6
|
+
MAX_FILE=4*1024*1024
|
|
7
|
+
MAX_TOTAL=8*1024*1024
|
|
8
|
+
|
|
9
|
+
def decode(item):
|
|
10
|
+
try:data=base64.b64decode(item['data'],validate=True)
|
|
11
|
+
except Exception:raise ValueError('Attachment encoding is invalid.')
|
|
12
|
+
if not data or len(data)>MAX_FILE:raise ValueError('Each attachment must be between 1 byte and 4 MB.')
|
|
13
|
+
return data
|
|
14
|
+
|
|
15
|
+
def diagram_text(data):
|
|
16
|
+
"""Decode draw.io XML locally; never fetch external resources or execute markup."""
|
|
17
|
+
def parse(raw):
|
|
18
|
+
if len(raw)>100000:raise ValueError('Diagram text exceeds 100,000 bytes. Use a smaller diagram.')
|
|
19
|
+
if b'<!DOCTYPE' in raw.upper() or b'<!ENTITY' in raw.upper():raise ValueError('Unsupported diagram XML declarations.')
|
|
20
|
+
try:return ElementTree.fromstring(raw)
|
|
21
|
+
except ElementTree.ParseError:raise ValueError('Cannot read diagram XML. Export a standard draw.io file or image.')
|
|
22
|
+
root=parse(data)
|
|
23
|
+
if root.tag=='mxGraphModel':return ElementTree.tostring(root,encoding='unicode')
|
|
24
|
+
if root.tag!='mxfile':raise ValueError('Use a draw.io mxfile or mxGraphModel diagram.')
|
|
25
|
+
pages=root.findall('diagram')
|
|
26
|
+
if not pages or len(pages)>20:raise ValueError('Use a diagram with between 1 and 20 pages.')
|
|
27
|
+
result=[]
|
|
28
|
+
for page in pages:
|
|
29
|
+
model=page.find('mxGraphModel')
|
|
30
|
+
if model is None:
|
|
31
|
+
try:
|
|
32
|
+
encoded=base64.b64decode((page.text or '').strip(),validate=True)
|
|
33
|
+
decoder=zlib.decompressobj(-15)
|
|
34
|
+
raw=decoder.decompress(encoded,100001)
|
|
35
|
+
if len(raw)>100000 or not decoder.eof or decoder.unused_data:raise ValueError('Diagram expansion exceeds the limit or is invalid.')
|
|
36
|
+
model=parse(unquote_to_bytes(raw.decode('utf-8')))
|
|
37
|
+
except (UnicodeError,zlib.error,ValueError) as exc:raise ValueError('Cannot decode this draw.io page within the supported text limit.') from exc
|
|
38
|
+
if model.tag!='mxGraphModel':raise ValueError('A draw.io page must contain an mxGraphModel.')
|
|
39
|
+
result.append('[Diagram: '+page.get('name','Untitled')+']\n'+ElementTree.tostring(model,encoding='unicode'))
|
|
40
|
+
text='\n\n'.join(result)
|
|
41
|
+
if len(text)>100000:raise ValueError('Combined diagram text exceeds 100,000 characters.')
|
|
42
|
+
return text
|
|
43
|
+
|
|
44
|
+
def extract(items):
|
|
45
|
+
if len(items)>4:raise ValueError('Attach up to four files per message.')
|
|
46
|
+
decoded=[(item,decode(item)) for item in items]
|
|
47
|
+
if sum(len(data) for _,data in decoded)>MAX_TOTAL:raise ValueError('Attachments exceed the 8 MB total limit.')
|
|
48
|
+
result=[]
|
|
49
|
+
for item,data in decoded:
|
|
50
|
+
mime=item['mime'];name=item['name']
|
|
51
|
+
if mime.startswith('image/'):
|
|
52
|
+
from PIL import Image
|
|
53
|
+
Image.MAX_IMAGE_PIXELS=20_000_000
|
|
54
|
+
with Image.open(io.BytesIO(data)) as im:
|
|
55
|
+
if im.width*im.height>20_000_000:raise ValueError('Image exceeds 20 megapixels.')
|
|
56
|
+
if im.format not in {'PNG','JPEG','WEBP'} or Image.MIME[im.format]!=mime:raise ValueError('Image format does not match its content.')
|
|
57
|
+
im.verify()
|
|
58
|
+
result.append({'name':name,'mime':mime,'data':item['data']});continue
|
|
59
|
+
if mime=='application/pdf':
|
|
60
|
+
from pypdf import PdfReader,overwrite_configuration
|
|
61
|
+
overwrite_configuration(maximum_declared_stream_length=8_000_000,zlib_maximum_output_length=8_000_000,lzw_maximum_output_length=8_000_000,run_length_maximum_output_length=8_000_000)
|
|
62
|
+
reader=PdfReader(io.BytesIO(data))
|
|
63
|
+
if reader.is_encrypted:raise ValueError('Unlock the PDF before attaching it.')
|
|
64
|
+
if len(reader.pages)>50:raise ValueError('Use a PDF with at most 50 pages.')
|
|
65
|
+
pages=[page.extract_text() or '' for page in reader.pages]
|
|
66
|
+
text='\n\n'.join(f'[Page {i+1}]\n{value}' for i,value in enumerate(pages))
|
|
67
|
+
if not any(value.strip() for value in pages):raise ValueError('This PDF has no readable text. Attach screenshots of the relevant pages instead.')
|
|
68
|
+
elif mime=='application/vnd.openxmlformats-officedocument.wordprocessingml.document':
|
|
69
|
+
with zipfile.ZipFile(io.BytesIO(data)) as archive:
|
|
70
|
+
if sum(i.file_size for i in archive.infolist())>16*1024*1024:raise ValueError('The expanded document exceeds 16 MB.')
|
|
71
|
+
xml=archive.read('word/document.xml')
|
|
72
|
+
if b'<!DOCTYPE' in xml or b'<!ENTITY' in xml:raise ValueError('Unsupported document XML.')
|
|
73
|
+
root=ElementTree.fromstring(xml)
|
|
74
|
+
text='\n'.join(''.join(p.itertext()) for p in root.iter('{http://schemas.openxmlformats.org/wordprocessingml/2006/main}p'))
|
|
75
|
+
elif mime=='text/plain' and name.lower().endswith(('.drawio','.xml')):text=diagram_text(data)
|
|
76
|
+
elif mime in {'text/plain','text/markdown','text/csv','application/json'}:text=data.decode('utf-8-sig')
|
|
77
|
+
else:raise ValueError('Use PNG, JPEG, WebP, PDF, DOCX, TXT, Markdown, CSV or JSON.')
|
|
78
|
+
if not text.strip():raise ValueError('The document has no readable text.')
|
|
79
|
+
if len(text)>100000:raise ValueError('Document text exceeds 100,000 characters. Attach a shorter excerpt.')
|
|
80
|
+
result.append({'name':name,'mime':mime,'text':text,'mode':'extracted text; embedded images and layout are not included'})
|
|
81
|
+
if sum(len(i.get('text','')) for i in result)>150000:raise ValueError('Combined document text exceeds 150,000 characters.')
|
|
82
|
+
return result
|
|
83
|
+
|
|
84
|
+
def prepare(items):
|
|
85
|
+
if not items:return []
|
|
86
|
+
try:
|
|
87
|
+
run=subprocess.run([sys.executable,str(Path(__file__).resolve()),'--worker'],input=json.dumps(items),text=True,capture_output=True,timeout=20)
|
|
88
|
+
response=json.loads(run.stdout)
|
|
89
|
+
if 'error' in response:raise RuntimeError(response['error'])
|
|
90
|
+
return response['attachments']
|
|
91
|
+
except (subprocess.TimeoutExpired,json.JSONDecodeError):raise RuntimeError('Attachment processing stopped. Try a smaller or simpler file.')
|
|
92
|
+
|
|
93
|
+
if __name__=='__main__':
|
|
94
|
+
try:
|
|
95
|
+
if sys.platform!='win32':
|
|
96
|
+
import resource
|
|
97
|
+
resource.setrlimit(resource.RLIMIT_CPU,(12,12))
|
|
98
|
+
if sys.platform!='darwin':resource.setrlimit(resource.RLIMIT_AS,(768*1024*1024,768*1024*1024))
|
|
99
|
+
print(json.dumps({'attachments':extract(json.load(sys.stdin))}))
|
|
100
|
+
except (ValueError,UnicodeError,zipfile.BadZipFile,KeyError) as exc:print(json.dumps({'error':str(exc)[:250]}))
|
|
101
|
+
except Exception:print(json.dumps({'error':'Cannot read this attachment. Export a standard PDF, DOCX, text file or image and try again.'}))
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Optional Azure/GCP clients; install after server/emulation-requirements.txt.
|
|
2
|
+
# IBM structured-runtime dependencies are isolated by scripts/setup-structured-runtime.py.
|
|
3
|
+
azure-core==1.41.0
|
|
4
|
+
azure-storage-blob==12.31.1
|
|
5
|
+
certifi==2026.10.23
|
|
6
|
+
cffi==2.1.1
|
|
7
|
+
charset-normalizer==3.5.2
|
|
8
|
+
cryptography==50.0.2
|
|
9
|
+
google-api-core==2.44.0
|
|
10
|
+
google-auth==2.62.0
|
|
11
|
+
google-cloud-core==2.8.0
|
|
12
|
+
google-cloud-storage==3.17.1
|
|
13
|
+
google-crc32c==1.9.0
|
|
14
|
+
google-resumable-media==2.11.0
|
|
15
|
+
googleapis-common-protos==1.76.0
|
|
16
|
+
idna==3.20
|
|
17
|
+
isodate==0.7.2
|
|
18
|
+
opentelemetry-api==1.45.2
|
|
19
|
+
proto-plus==1.29.0
|
|
20
|
+
protobuf==7.36.2
|
|
21
|
+
pyasn1==0.6.5
|
|
22
|
+
pyasn1_modules==0.4.2
|
|
23
|
+
pycparser==3.12
|
|
24
|
+
requests==2.34.2
|
|
25
|
+
typing_extensions==4.16.0
|
|
26
|
+
urllib3==2.8.0
|
|
27
|
+
|
|
28
|
+
# Public FAQ real HTTP API v2 event adapter (runtime wheel independently hash-pinned in emitted source).
|
|
29
|
+
mangum==0.22.0
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"""Persistent Codex protocol transport for the engineering-session foundation.
|
|
2
|
+
|
|
3
|
+
Not a sandbox, execution policy or public endpoint. Callers must separately qualify
|
|
4
|
+
workspace isolation and tools before exposing engineering turns to the product.
|
|
5
|
+
Uses the official signed-in CLI; never reads or extracts account tokens.
|
|
6
|
+
"""
|
|
7
|
+
import asyncio
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
import signal
|
|
12
|
+
from .local_providers import account_environment
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ProtocolError(RuntimeError):
|
|
16
|
+
def __init__(self, message, *, code=None, category=None):
|
|
17
|
+
super().__init__(message)
|
|
18
|
+
self.code = code
|
|
19
|
+
self.category = category
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class CodexAppServer:
|
|
23
|
+
def __init__(self, workspace, *, command=None, event_limit=4096, experimental=False):
|
|
24
|
+
self.workspace = Path(workspace).resolve(strict=True)
|
|
25
|
+
if not self.workspace.is_dir():
|
|
26
|
+
raise ValueError('Codex workspace must be an existing directory')
|
|
27
|
+
self.command = command or ['codex', 'app-server', '--listen', 'stdio://',
|
|
28
|
+
'-c', 'analytics.enabled=false']
|
|
29
|
+
self.experimental = experimental
|
|
30
|
+
self.events = asyncio.Queue(maxsize=event_limit)
|
|
31
|
+
self.process = None
|
|
32
|
+
self.pending = {}
|
|
33
|
+
self.serial = 0
|
|
34
|
+
self.failure = None
|
|
35
|
+
self.closed = asyncio.Event()
|
|
36
|
+
self.reader = self.stderr_reader = None
|
|
37
|
+
self.write_lock = asyncio.Lock()
|
|
38
|
+
self.dynamic_tool_handler = None
|
|
39
|
+
self.tool_tasks = set()
|
|
40
|
+
|
|
41
|
+
async def start(self):
|
|
42
|
+
if self.process is not None:
|
|
43
|
+
raise ProtocolError('Codex transport has already started')
|
|
44
|
+
env = account_environment()
|
|
45
|
+
# Authentication remains CLI-owned. Do not forward deployment credentials.
|
|
46
|
+
for key in list(env):
|
|
47
|
+
if key.startswith(('AWS_', 'AZURE_', 'GOOGLE_', 'GCLOUD_', 'IBM_', 'WATSONX_', 'TF_')) or key in {'KUBECONFIG', 'DOCKER_HOST', 'DOCKER_CONFIG', 'CLOUDSDK_CONFIG', 'GOOGLE_APPLICATION_CREDENTIALS'}:
|
|
48
|
+
env.pop(key, None)
|
|
49
|
+
self.process = await asyncio.create_subprocess_exec(
|
|
50
|
+
*self.command, cwd=self.workspace, env=env,
|
|
51
|
+
stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE,
|
|
52
|
+
stderr=asyncio.subprocess.PIPE, limit=8_000_000, start_new_session=True)
|
|
53
|
+
self.reader = asyncio.create_task(self._read())
|
|
54
|
+
self.stderr_reader = asyncio.create_task(self._drain_stderr())
|
|
55
|
+
try:
|
|
56
|
+
result = await self.request('initialize', {'clientInfo': {
|
|
57
|
+
'name': 'atmem_ai_architect', 'title': 'AtMem AI Architect',
|
|
58
|
+
'version': json.loads((Path(__file__).resolve().parents[1] / 'package.json').read_text())['version']},
|
|
59
|
+
**({'capabilities': {'experimentalApi': True}} if self.experimental else {})})
|
|
60
|
+
await self._write({'method': 'initialized', 'params': {}})
|
|
61
|
+
return result
|
|
62
|
+
except BaseException:
|
|
63
|
+
await self.close()
|
|
64
|
+
raise
|
|
65
|
+
|
|
66
|
+
async def _write(self, message):
|
|
67
|
+
if self.failure:
|
|
68
|
+
raise ProtocolError(self.failure)
|
|
69
|
+
if not self.process or self.process.returncode is not None:
|
|
70
|
+
raise ProtocolError('Codex transport is not running')
|
|
71
|
+
wire = json.dumps(message, allow_nan=False, separators=(',', ':')).encode() + b'\n'
|
|
72
|
+
if len(wire) > 8_000_000:
|
|
73
|
+
raise ValueError('Codex protocol message exceeds the explicit bound')
|
|
74
|
+
async with self.write_lock:
|
|
75
|
+
self.process.stdin.write(wire)
|
|
76
|
+
await self.process.stdin.drain()
|
|
77
|
+
|
|
78
|
+
async def request(self, method, params=None, *, timeout=30):
|
|
79
|
+
if not isinstance(method, str) or not method:
|
|
80
|
+
raise ValueError('A protocol method is required')
|
|
81
|
+
self.serial += 1
|
|
82
|
+
ident = self.serial
|
|
83
|
+
future = asyncio.get_running_loop().create_future()
|
|
84
|
+
self.pending[ident] = future
|
|
85
|
+
try:
|
|
86
|
+
await self._write({'id': ident, 'method': method, 'params': params or {}})
|
|
87
|
+
return await asyncio.wait_for(future, timeout)
|
|
88
|
+
except BaseException:
|
|
89
|
+
# _fail may settle this future while a write is failing. Consume its
|
|
90
|
+
# exception so cancellation/transport errors never leak orphan futures.
|
|
91
|
+
if future.done() and not future.cancelled():
|
|
92
|
+
future.exception()
|
|
93
|
+
raise
|
|
94
|
+
finally:
|
|
95
|
+
self.pending.pop(ident, None)
|
|
96
|
+
if not future.done():
|
|
97
|
+
future.cancel()
|
|
98
|
+
# A timeout/cancel only stops waiting; it does not cancel a Codex turn.
|
|
99
|
+
# Engineering callers must use turn/interrupt and observe its terminal event.
|
|
100
|
+
|
|
101
|
+
async def notification(self, *, timeout=30):
|
|
102
|
+
if not self.events.empty():
|
|
103
|
+
return self.events.get_nowait()
|
|
104
|
+
if self.failure:
|
|
105
|
+
raise ProtocolError(self.failure)
|
|
106
|
+
received = asyncio.create_task(self.events.get())
|
|
107
|
+
closed = asyncio.create_task(self.closed.wait())
|
|
108
|
+
try:
|
|
109
|
+
done, _ = await asyncio.wait({received, closed}, timeout=timeout,
|
|
110
|
+
return_when=asyncio.FIRST_COMPLETED)
|
|
111
|
+
if received in done:
|
|
112
|
+
return received.result()
|
|
113
|
+
if closed in done:
|
|
114
|
+
raise ProtocolError(self.failure)
|
|
115
|
+
raise asyncio.TimeoutError('No Codex event arrived within the observation window')
|
|
116
|
+
finally:
|
|
117
|
+
for task in (received, closed):
|
|
118
|
+
if not task.done():
|
|
119
|
+
task.cancel()
|
|
120
|
+
await asyncio.gather(received, closed, return_exceptions=True)
|
|
121
|
+
|
|
122
|
+
def _fail(self, reason):
|
|
123
|
+
self.failure = reason
|
|
124
|
+
self.closed.set()
|
|
125
|
+
for future in self.pending.values():
|
|
126
|
+
if not future.done():
|
|
127
|
+
future.set_exception(ProtocolError(reason))
|
|
128
|
+
|
|
129
|
+
async def _read(self):
|
|
130
|
+
try:
|
|
131
|
+
while line := await self.process.stdout.readline():
|
|
132
|
+
message = json.loads(line)
|
|
133
|
+
if not isinstance(message, dict):
|
|
134
|
+
raise ProtocolError('Codex returned an invalid protocol envelope')
|
|
135
|
+
if 'method' in message:
|
|
136
|
+
if 'id' in message:
|
|
137
|
+
if message['method']=='item/tool/call' and self.dynamic_tool_handler is not None and len(self.tool_tasks)<8:
|
|
138
|
+
# Never block protocol responses/progress on a tool.
|
|
139
|
+
# Only this exact callback is enabled; approvals stay denied.
|
|
140
|
+
task=asyncio.create_task(self._tool_reply(message))
|
|
141
|
+
self.tool_tasks.add(task)
|
|
142
|
+
task.add_done_callback(self.tool_tasks.discard)
|
|
143
|
+
else:
|
|
144
|
+
await self._write({'id': message['id'], 'error': {
|
|
145
|
+
'code': -32601, 'message': 'Client handler is not enabled'}})
|
|
146
|
+
else:
|
|
147
|
+
self.events.put_nowait(message)
|
|
148
|
+
elif 'id' in message:
|
|
149
|
+
future = self.pending.get(message['id'])
|
|
150
|
+
if future and not future.done():
|
|
151
|
+
if 'error' in message:
|
|
152
|
+
code = message['error'].get('code') if isinstance(message['error'], dict) else None
|
|
153
|
+
# Retain only a narrow recovery classification; never
|
|
154
|
+
# expose the server's raw diagnostics or local paths.
|
|
155
|
+
diagnostic = message['error'].get('message', '') if isinstance(message['error'], dict) else ''
|
|
156
|
+
category = 'missing_thread' if code == -32600 and isinstance(diagnostic, str) and diagnostic.startswith('no rollout found for thread id ') else None
|
|
157
|
+
future.set_exception(ProtocolError(f'Codex request rejected (code {code})', code=code, category=category))
|
|
158
|
+
elif 'result' in message:
|
|
159
|
+
future.set_result(message['result'])
|
|
160
|
+
else:
|
|
161
|
+
raise ProtocolError('Codex response contains neither result nor error')
|
|
162
|
+
else:
|
|
163
|
+
raise ProtocolError('Codex protocol envelope has no method or id')
|
|
164
|
+
self._fail('Codex transport closed; pending work is not confirmed complete')
|
|
165
|
+
except asyncio.CancelledError:
|
|
166
|
+
raise
|
|
167
|
+
except Exception:
|
|
168
|
+
self._fail('Codex protocol failed or event capacity was exceeded; no completion is inferred')
|
|
169
|
+
if self.process.returncode is None:
|
|
170
|
+
self.process.terminate()
|
|
171
|
+
|
|
172
|
+
async def _drain_stderr(self):
|
|
173
|
+
# Do not leak credentials, local paths or provider diagnostic bodies into
|
|
174
|
+
# public reports. Drain to avoid deadlock; qualification stores safe receipts.
|
|
175
|
+
while await self.process.stderr.read(65536):
|
|
176
|
+
pass
|
|
177
|
+
|
|
178
|
+
async def _tool_reply(self,message):
|
|
179
|
+
try:
|
|
180
|
+
result=await asyncio.wait_for(self.dynamic_tool_handler(message.get('params',{})),30)
|
|
181
|
+
if not isinstance(result,dict) or set(result)!={'success','contentItems'} or type(result['success']) is not bool:
|
|
182
|
+
raise ValueError('Invalid tool response')
|
|
183
|
+
if not isinstance(result['contentItems'],list) or any(not isinstance(item,dict) or set(item)!={'type','text'} or item['type']!='inputText' or not isinstance(item['text'],str) for item in result['contentItems']):
|
|
184
|
+
raise ValueError('Only bounded text evidence is enabled')
|
|
185
|
+
if len(json.dumps(result,allow_nan=False).encode())>64000:raise ValueError('Tool response exceeds bound')
|
|
186
|
+
except asyncio.CancelledError:
|
|
187
|
+
raise
|
|
188
|
+
except Exception:
|
|
189
|
+
result={'success':False,'contentItems':[{'type':'inputText','text':'The registered engineering tool could not confirm this request. No success or work replay is inferred.'}]}
|
|
190
|
+
try:await self._write({'id':message['id'],'result':result})
|
|
191
|
+
except Exception:pass # Durable tool state survives a lost transport reply.
|
|
192
|
+
|
|
193
|
+
async def close(self):
|
|
194
|
+
if not self.process:
|
|
195
|
+
return
|
|
196
|
+
self._fail('Codex transport closed; pending work is not confirmed complete')
|
|
197
|
+
for task in self.tool_tasks:task.cancel()
|
|
198
|
+
await asyncio.gather(*list(self.tool_tasks),return_exceptions=True)
|
|
199
|
+
if self.process.returncode is None:
|
|
200
|
+
self.process.stdin.close()
|
|
201
|
+
try:
|
|
202
|
+
await asyncio.wait_for(self.process.wait(), 2)
|
|
203
|
+
except asyncio.TimeoutError:
|
|
204
|
+
try:
|
|
205
|
+
os.killpg(self.process.pid, signal.SIGTERM)
|
|
206
|
+
except ProcessLookupError:
|
|
207
|
+
pass
|
|
208
|
+
try:
|
|
209
|
+
await asyncio.wait_for(self.process.wait(), 2)
|
|
210
|
+
except asyncio.TimeoutError:
|
|
211
|
+
try:
|
|
212
|
+
os.killpg(self.process.pid, signal.SIGKILL)
|
|
213
|
+
except ProcessLookupError:
|
|
214
|
+
pass
|
|
215
|
+
await self.process.wait()
|
|
216
|
+
for task in (self.reader, self.stderr_reader):
|
|
217
|
+
if task:
|
|
218
|
+
task.cancel()
|
|
219
|
+
await asyncio.gather(*(t for t in (self.reader, self.stderr_reader) if t), return_exceptions=True)
|