@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,91 @@
|
|
|
1
|
+
"""Local-only, session-authenticated dictation. The app boundary owns HTTP auth."""
|
|
2
|
+
import asyncio, base64, io, json, os, shutil, wave
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from fastapi import APIRouter, HTTPException, Request
|
|
5
|
+
from .settings import setting
|
|
6
|
+
|
|
7
|
+
router=APIRouter()
|
|
8
|
+
ROOT=Path(__file__).resolve().parent
|
|
9
|
+
|
|
10
|
+
def configuration():
|
|
11
|
+
binary=shutil.which('whisper')
|
|
12
|
+
model=Path(setting('WHISPER_MODEL') or Path.home()/'.cache'/'whisper'/'tiny.en.pt')
|
|
13
|
+
if not binary or not model.is_file():return None
|
|
14
|
+
try: python=Path(binary).read_text().splitlines()[0].removeprefix('#!').strip()
|
|
15
|
+
except (OSError,IndexError,UnicodeError):return None
|
|
16
|
+
if not python.startswith('/') or not Path(python).is_file():return None
|
|
17
|
+
return python,model
|
|
18
|
+
|
|
19
|
+
class LocalSpeech:
|
|
20
|
+
def __init__(self):self.process=None;self.lock=asyncio.Lock()
|
|
21
|
+
async def close(self):
|
|
22
|
+
p=self.process;self.process=None
|
|
23
|
+
if p and p.returncode is None:
|
|
24
|
+
p.terminate()
|
|
25
|
+
try:await asyncio.wait_for(p.wait(),3)
|
|
26
|
+
except asyncio.TimeoutError:p.kill();await p.wait()
|
|
27
|
+
async def ready(self):
|
|
28
|
+
config=configuration()
|
|
29
|
+
if not config:raise HTTPException(503,'Local voice is not prepared. Run python3 scripts/setup-voice.py, then try again.')
|
|
30
|
+
if self.process and self.process.returncode is None:return
|
|
31
|
+
python,model=config
|
|
32
|
+
self.process=await asyncio.create_subprocess_exec(python,str(ROOT/'voice_worker.py'),str(model),
|
|
33
|
+
stdin=asyncio.subprocess.PIPE,stdout=asyncio.subprocess.PIPE,stderr=asyncio.subprocess.DEVNULL,
|
|
34
|
+
limit=100000)
|
|
35
|
+
try:
|
|
36
|
+
hello=json.loads(await asyncio.wait_for(self.process.stdout.readline(),30))
|
|
37
|
+
if hello.get('ready') is not True:raise ValueError('worker startup')
|
|
38
|
+
except BaseException:
|
|
39
|
+
await self.close();raise
|
|
40
|
+
async def prepare(self):
|
|
41
|
+
async with self.lock:await self.ready()
|
|
42
|
+
async def transcribe(self,pcm):
|
|
43
|
+
# A first partial can arrive while the page is warming the model. Wait for
|
|
44
|
+
# that preparation instead of turning an ordinary warmup into a mic failure.
|
|
45
|
+
try:await asyncio.wait_for(self.lock.acquire(),35)
|
|
46
|
+
except asyncio.TimeoutError:raise HTTPException(503,'Local transcription is busy. Finish or stop another recording, then try again.')
|
|
47
|
+
try:
|
|
48
|
+
try:
|
|
49
|
+
await self.ready()
|
|
50
|
+
self.process.stdin.write((json.dumps({'pcm':base64.b64encode(pcm).decode()})+'\n').encode())
|
|
51
|
+
await self.process.stdin.drain()
|
|
52
|
+
result=json.loads(await asyncio.wait_for(self.process.stdout.readline(),25))
|
|
53
|
+
if not isinstance(result.get('text'),str):raise ValueError('worker reply')
|
|
54
|
+
return result['text']
|
|
55
|
+
except HTTPException:raise
|
|
56
|
+
except BaseException:
|
|
57
|
+
await self.close();raise
|
|
58
|
+
finally:self.lock.release()
|
|
59
|
+
|
|
60
|
+
engine=LocalSpeech()
|
|
61
|
+
|
|
62
|
+
@router.get('/api/voice/status')
|
|
63
|
+
async def status():
|
|
64
|
+
return {'available':configuration() is not None,'engine':'local-whisper','audioStored':False,'maxSeconds':60}
|
|
65
|
+
|
|
66
|
+
@router.post('/api/voice/prepare')
|
|
67
|
+
async def prepare():
|
|
68
|
+
try:await engine.prepare();return {'ready':True}
|
|
69
|
+
except HTTPException:raise
|
|
70
|
+
except Exception:raise HTTPException(503,'Local speech recognition could not start. Check the Whisper installation.')
|
|
71
|
+
|
|
72
|
+
@router.post('/api/voice/transcribe')
|
|
73
|
+
async def transcribe(request:Request):
|
|
74
|
+
if request.headers.get('content-type','').split(';')[0]!='audio/wav':
|
|
75
|
+
raise HTTPException(415,'Send mono 16 kHz PCM WAV audio.')
|
|
76
|
+
body=await request.body()
|
|
77
|
+
if len(body)>1_920_100:raise HTTPException(413,'Voice clips are limited to 60 seconds.')
|
|
78
|
+
try:
|
|
79
|
+
with wave.open(io.BytesIO(body),'rb') as audio:
|
|
80
|
+
if (audio.getnchannels(),audio.getsampwidth(),audio.getframerate(),audio.getcomptype())!=(1,2,16000,'NONE'):
|
|
81
|
+
raise ValueError('format')
|
|
82
|
+
frames=audio.getnframes()
|
|
83
|
+
if not 1600<=frames<=960000:raise ValueError('duration')
|
|
84
|
+
pcm=audio.readframes(frames)
|
|
85
|
+
if len(pcm)!=frames*2:raise ValueError('truncated')
|
|
86
|
+
except (ValueError,EOFError,wave.Error):raise HTTPException(422,'Invalid audio. Use a mono 16 kHz PCM WAV clip of up to 60 seconds.')
|
|
87
|
+
try:
|
|
88
|
+
text=await engine.transcribe(pcm)
|
|
89
|
+
return {'text':text,'engine':'local-whisper','audioStored':False}
|
|
90
|
+
except HTTPException:raise
|
|
91
|
+
except Exception:raise HTTPException(503,'Local transcription was interrupted. Your message has not been sent.')
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Private local worker: bounded PCM requests via stdin, text via stdout. No audio files."""
|
|
2
|
+
import base64, json, os, sys
|
|
3
|
+
import numpy as np
|
|
4
|
+
import torch
|
|
5
|
+
import whisper
|
|
6
|
+
|
|
7
|
+
torch.set_num_threads(4)
|
|
8
|
+
model = whisper.load_model(sys.argv[1], device='cpu') # Exact existing checkpoint; never downloads.
|
|
9
|
+
print(json.dumps({'ready': True}), flush=True)
|
|
10
|
+
for line in sys.stdin:
|
|
11
|
+
try:
|
|
12
|
+
payload=json.loads(line)
|
|
13
|
+
raw=base64.b64decode(payload['pcm'], validate=True)
|
|
14
|
+
if not 3200 <= len(raw) <= 1_920_000 or len(raw)%2:
|
|
15
|
+
raise ValueError('audio size')
|
|
16
|
+
samples=np.frombuffer(raw,dtype='<i2').astype(np.float32)/32768
|
|
17
|
+
if np.sqrt(np.mean(samples*samples)) < .003:
|
|
18
|
+
text=''
|
|
19
|
+
else:
|
|
20
|
+
result=model.transcribe(samples,language='en',fp16=False,temperature=0,
|
|
21
|
+
condition_on_previous_text=False,verbose=None)
|
|
22
|
+
text=' '.join(s['text'].strip() for s in result.get('segments',[])
|
|
23
|
+
if s.get('no_speech_prob',0)<.8).strip()
|
|
24
|
+
print(json.dumps({'text':text[:12000]}),flush=True)
|
|
25
|
+
except Exception:
|
|
26
|
+
print(json.dumps({'error':'Local transcription failed.'}),flush=True)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "ibm-generated-source-local-qualification",
|
|
3
|
+
"checks": [
|
|
4
|
+
{
|
|
5
|
+
"name": "block_776f726b7370616365-dependency-closure",
|
|
6
|
+
"passed": true,
|
|
7
|
+
"exitCode": 0,
|
|
8
|
+
"error": null,
|
|
9
|
+
"logSha256": "7cdf86c11be8cd2bd27e079b9eaf3e1a49e67fd3859d15322472a4c2cd670aaf"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"name": "block_776f726b7370616365-runtime",
|
|
13
|
+
"passed": true,
|
|
14
|
+
"exitCode": 0,
|
|
15
|
+
"error": null,
|
|
16
|
+
"logSha256": "e4a87143fa2b5fcad8312a350ec9bfa971d8e09a657b9949f2ca21c087789bda"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "provider-init",
|
|
20
|
+
"passed": true,
|
|
21
|
+
"exitCode": 0,
|
|
22
|
+
"error": null,
|
|
23
|
+
"logSha256": "4dd3e891182a46feed67ba9f9071884ed31574ba3279bc8fbc1a8b86867d69e3"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "provider-schema",
|
|
27
|
+
"passed": true,
|
|
28
|
+
"exitCode": 0,
|
|
29
|
+
"error": null,
|
|
30
|
+
"logSha256": "624bd9c40454b477e270d3078d4f93fae51fe8cd939b1b0da055f03794c336fe"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "provider-mocks",
|
|
34
|
+
"passed": true,
|
|
35
|
+
"exitCode": 0,
|
|
36
|
+
"error": null,
|
|
37
|
+
"logSha256": "bb92f233a7936f4de6a41314bb2881369aaa623d150a82eb78f43a7b339798c5"
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"passed": true,
|
|
41
|
+
"cloudOperations": false,
|
|
42
|
+
"artifactHashes": {
|
|
43
|
+
"applications/block_776f726b7370616365/ibm_structured.py": "e1ee0f1bc06f4b6f15954d9d53e4ce0f218cf791ea6098b95a7fccb77b112fda",
|
|
44
|
+
"applications/block_776f726b7370616365/ibm_acceptance.py": "1dae539a44bc4878a9ce5b1552f2e8758512625058247a88e3762c9464c20379",
|
|
45
|
+
"applications/block_776f726b7370616365/structured_output.py": "432c730c54bd7dcae7b52fb73edc67d2e7b44b890e68254fdee832cb4c2304bc",
|
|
46
|
+
"applications/block_776f726b7370616365/structured_http.py": "fae1e7d092c1d17e90cb2af41aeb19ce786b38a1a813427197b1ad56dd0006ab",
|
|
47
|
+
"applications/block_776f726b7370616365/http_acceptance.py": "bd9ed35d684e1b3139b13f2cda948e1008b71d518080257382139c12e7cfa44e",
|
|
48
|
+
"applications/block_776f726b7370616365/export_contract_acceptance.py": "da3e116e83592fac21287eebb23805c5b2c876464b84348586a0d0fa417b8445",
|
|
49
|
+
"applications/block_776f726b7370616365/policy_review.py": "66d56df0dcab7df4ef85c35cc8a0ddbc7e71f8b31179db4916898c9ea5c4e947",
|
|
50
|
+
"applications/block_776f726b7370616365/web/index.html": "acc94cd6ca367c30b16b313ec6f79e33b9c0525fdf1e7c9078a9ee3d106b3b55",
|
|
51
|
+
"applications/block_776f726b7370616365/web/app.css": "b8a25941eaaa678e871b7f0b9ce6c9729680955bc55cf8ac231b12d18bb4bb8c",
|
|
52
|
+
"applications/block_776f726b7370616365/web/app.js": "35e3cf9badd3d69a8653e1787e3a0b40ec6bbfaaf1d8e33f9dbbe78643a8184a",
|
|
53
|
+
"applications/block_776f726b7370616365/output-contract.json": "ddbb7e23a60d0d9b3504a5ae419d756e03d12e955f20c188f81c4e5800fa33bf",
|
|
54
|
+
"applications/block_776f726b7370616365/requirements.lock": "5f1c4a8a5e6913bcabb02f7ecfbbeed46d662d0d69e75be289285906607b28ac",
|
|
55
|
+
"applications/block_776f726b7370616365/dependency-sources.json": "4c9fc025adc10ff43708c84f34cfa50a9f36eeb7ea77ae0a240bcc7c3f73ebe7",
|
|
56
|
+
"applications/block_776f726b7370616365/test-requirements.lock": "54894d4de170917d97979422e764854555ad23ff16c253128540602cc1791bf0",
|
|
57
|
+
"applications/block_776f726b7370616365/test-dependency-sources.json": "8a4c9c3daff2e034da95e9dad9916d46cb7eb1b228b2f940c7e200698f9c1a64",
|
|
58
|
+
"applications/block_776f726b7370616365/container-base.json": "b2adfde9b3215f7f0299806e211b49438be95ea3c2b995e905452cce2dfd0650",
|
|
59
|
+
"applications/block_776f726b7370616365/Dockerfile": "89e80555673c3d5b8c46d6101a2c256a5fd1ab94350a1fd971338b06c3ee9f72",
|
|
60
|
+
"applications/block_776f726b7370616365/.dockerignore": "29166c81d104dea78a0a4ea844ed15161843c68c726baf32952ab72f84f12bf4",
|
|
61
|
+
"applications/block_776f726b7370616365/BUILD.md": "ba89ea7d249c8237b4e5e9502af0757a7f345ef3140254395b8088caec8f5118",
|
|
62
|
+
".terraform.lock.hcl": "022cd3d744cf400f91bc98094840a94eb8e652d67447d744db359be463a3cdb1",
|
|
63
|
+
"main.tf.json": "acc18e4f2a10015ef140d8cf6939e5a9f65a5bc9a73b25c3cbb46dc6547bcda6",
|
|
64
|
+
"resource-schedule.json": "5b9c183deb64cca36f410bd55f2a70ff2167767edade395ace2be57becf6c72c",
|
|
65
|
+
"deployment.tfvars.json.example": "dc09b358146fd0298f748de15b209642373629566d0d52c30a1d8879610573c0",
|
|
66
|
+
".gitignore": "8168883c9173f4d7fe176e5e8ebdc1dfb569fd81efd2e3da0a207e7f27e1dd95",
|
|
67
|
+
"tests/ibm-structured.tftest.hcl": "621fbc196133d3f2ddae78a882842554109a00ba53cc5ef858056dc0cb20e3b2",
|
|
68
|
+
"README.md": "cf23af0d5732b986f63655295688e84c4ac24be2605f32ee55c52fc4ab80e75a",
|
|
69
|
+
"generation-quality.json": "d85052d36245473287c2de14b11f4851006097694ffbe32ceed8bf1cd83fef6d"
|
|
70
|
+
},
|
|
71
|
+
"boundary": "Emitted Python 3.13 source, real cryptographic/ASGI tests with scripted provider key/model/policy transport and denied external sockets; native Terraform schemas and mock plans. No container image startup/scan, provider account plan, identity sign-in/MFA/revocation, real model-quality test or deployment."
|
|
72
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "local-durable-workflow-core",
|
|
3
|
+
"recordedAt": "2026-11-09T23:58:36.893280+00:00",
|
|
4
|
+
"passed": true,
|
|
5
|
+
"tests": 54,
|
|
6
|
+
"seconds": 12.997,
|
|
7
|
+
"python": "3.13.14 (main, Jun 10 2026, 12:24:04) [Clang 21.0.0 (clang-2100.0.123.102)]",
|
|
8
|
+
"postgresVersion": "17.11",
|
|
9
|
+
"schemaVersion": 1,
|
|
10
|
+
"schemaSha256": "fe15a655c14eeda37bc3e4e60f0270de7bcb86d79ea9da4577246dca15806e59",
|
|
11
|
+
"queueVersion": "3.10.0",
|
|
12
|
+
"sourceHashes": {
|
|
13
|
+
"scripts/initialize-durable-fixture.py": "1bbca33ca680b2ed69f75ccc9da2bdd8aaf02c79e00a6b9979f71f1c88ace82f",
|
|
14
|
+
"scripts/qualify-durable-runtime.py": "a106ff913b0146b108b3d94a5199b4abe8011fcc7f72a9d1113cc6c886424b8a",
|
|
15
|
+
"scripts/setup-durable-runtime.py": "d916a93910a1ac2e24ac63f6ab96561f0a5d98727383b010376f3d467271131f",
|
|
16
|
+
"scripts/start-durable-fixture.py": "eb4f609c5bd00bde2ca560d495f80c62fdf88088a65bf564239ee216d991a2cc",
|
|
17
|
+
"src/runtime/approved_http_destination.py": "dbe62ce035d16c8e2988d2672d25be8597d963bab6b0fc969aa59b240d0aa442",
|
|
18
|
+
"src/runtime/durable-python-lock.json": "dbaa350d227c74f4acf046a27d878f3fa78ce762a5c58ba832b70c20a083cf87",
|
|
19
|
+
"src/runtime/durable_workflow.py": "5d31e1de487d2522c706cfbebcad5e880ce762a859b8804b23e86bb3df074675",
|
|
20
|
+
"src/runtime/postgres-qualification-lock.json": "bc475f763854dc4b1ea3afc930ad312aad1b76d93f69fad8244207c6aadf0b45",
|
|
21
|
+
"src/runtime/workflow_contract.py": "e662aeb89bcd4eac9c34b32b6a154de8a1758ae089eee71f0642d27e1b413eb4",
|
|
22
|
+
"src/runtime/workflow_database.py": "178b03c7b10bd56b6eb431366b57416dc8059db1a2cec4657de2f2c4cc8d0799",
|
|
23
|
+
"src/runtime/workflow_errors.py": "753d82e5a788ac459cb2b106c078af86cd90077886cda42767a36f62159fd19b",
|
|
24
|
+
"src/runtime/workflow_process_stage.py": "b1d6f7fd8aa679107f2ae4c1ec885c1693ee84422e6cb1af20d6f43a06ff31f6",
|
|
25
|
+
"src/runtime/workflow_schema.sql": "fe15a655c14eeda37bc3e4e60f0270de7bcb86d79ea9da4577246dca15806e59",
|
|
26
|
+
"src/runtime/workflow_worker.py": "c1a6f368eb42128a9648f4c324a5891c87daf6b9723951e74fb3f07963640f69",
|
|
27
|
+
"tests/runtime/durable_crash_acceptance.py": "bd1c0acd58972da8b04db1b2d0f0fa570a2223791ce399ebe750d59f1d92e197",
|
|
28
|
+
"tests/runtime/durable_fixture_tasks.py": "f9a20d3aad51ab69e4e4092c20d6f84b097fcbef5c9a3eccf4baa0420cd82515",
|
|
29
|
+
"tests/runtime/durable_http_acceptance.py": "4ef564c4e4a1120867789f48d85d21e5d19f06a978e5c01cb5a3ec96ddb75c17",
|
|
30
|
+
"tests/runtime/durable_postgres_acceptance.py": "6e8a9d26eb41611963245ab8d4fad3767d908843050ca47021128a9c55d94be3",
|
|
31
|
+
"tests/runtime/durable_privileges_acceptance.py": "fff2903ef7c7a9f951e980691f6e812b0dc55f0bece9d08b100c01282e730ebb",
|
|
32
|
+
"tests/runtime/durable_recovery_acceptance.py": "008ddb5739ac6a4d71f20e374ffb69ccf04a9f18bb2225b12367cdf6763dcaf9",
|
|
33
|
+
"tests/runtime/durable_restricted_worker_acceptance.py": "2934ffab683c87d3467f6a74ede7ae6c1b00613c53de900b7dc3d8f706168f77",
|
|
34
|
+
"tests/runtime/durable_stage_acceptance.py": "56319b3d6ff64bddc84a27535d495f41fd5a42c29be62221940198203f05acee",
|
|
35
|
+
"tests/runtime/durable_tls_deadline_acceptance.py": "65f28bb754b6ca944353623afb39a4665705d8c09fd0cb9763e35a935d759ed1",
|
|
36
|
+
"tests/runtime/durable_worker_acceptance.py": "9f8bcce3760186a37c8ca35b8ca8d7de14f0ba49f0dd6691fac178fd4cff55aa",
|
|
37
|
+
"tests/runtime/durable_worker_process.py": "ab224adac36773db78cc7f732319a03ea31c1a8153b791c75a0189d5aee466f8",
|
|
38
|
+
"tests/runtime/invoice_document_acceptance.py": "a170a5af6aeedde0a86f516a50286bcaf3eb7bb743b97c38bc8c78e8a3331410",
|
|
39
|
+
"tests/runtime/invoice_extraction_acceptance.py": "783b00b4cb127cfe6594a0b22bc10ffc1ee68a03b477c60c87be1837e7b01bce",
|
|
40
|
+
"tests/runtime/invoice_http_acceptance.py": "078595b3e5c4f026916204e82b769b08dba73265a7bd99b9b2d3e129346112ab",
|
|
41
|
+
"tests/runtime/invoice_storage_acceptance.py": "b4a0ae395d3299353f1a97eac4989e5522e015f677605d4f2c24d1a4f202ef13",
|
|
42
|
+
"tests/runtime/workflow_stage_child_fixture.py": "14747c71b2b7bfbe71c6d05026dfb79c655f9d4b35af8439eaced4b3d57a3f50",
|
|
43
|
+
"tests/runtime/workflow_tls_destination_fixture.py": "9924ccafb80af31250d6f2fa9913731a46ba6ee9bc0b90661f2daa211944e79a"
|
|
44
|
+
},
|
|
45
|
+
"sourcesUnchangedDuringChecks": true,
|
|
46
|
+
"checks": [
|
|
47
|
+
{
|
|
48
|
+
"check": "dependency-check",
|
|
49
|
+
"exitCode": 0,
|
|
50
|
+
"log": "dependency-check.log"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"check": "workflow-acceptance",
|
|
54
|
+
"exitCode": 0,
|
|
55
|
+
"log": "workflow-acceptance.log"
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"evidenceBoundary": "Real local PostgreSQL, native queue workers, restricted local DB logins, SIGKILL replacements, loopback TLS and child process deadlines; synthetic processors and destinations. No native cloud/IdP/PDF/model/vendor, complete project, backup/restore, full matrix or deployment claim.",
|
|
59
|
+
"cloudOperations": false,
|
|
60
|
+
"full28CaseAcceptanceComplete": false
|
|
61
|
+
}
|
package/specs/029-general-purpose-engine/evidence/20261111-runtime-dependencies/sdk/receipt.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"passed": true,
|
|
3
|
+
"catalogSha256": "7d5397350e80330d09d1b2a8e838936d82b0dc3159680d26d064f459b0a269af",
|
|
4
|
+
"artifactSha256": "4dbff53c715e9f644d41a82e4cdc9e61f45048d80be8af3c11bf0c7d7bfb3c69",
|
|
5
|
+
"oracleSha256": "f8c997f0ed93feb6a44738bc8fcf0aa62d8aa40668e7ac922354eecd38514af4",
|
|
6
|
+
"results": [
|
|
7
|
+
{
|
|
8
|
+
"runtime": "lambda-python312-tests",
|
|
9
|
+
"status": "passed",
|
|
10
|
+
"imageId": "sha256:cdb746c1eb56b61de56e1b5e78f6194392eb00494a1bb257a592852e72d8314b",
|
|
11
|
+
"platform": "linux/arm64"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"runtime": "python-tests",
|
|
15
|
+
"status": "passed",
|
|
16
|
+
"imageId": "sha256:48d884813cf44e927cf64c5529dd630dd3b18338c6dc727991eef9b71e934a20",
|
|
17
|
+
"platform": "linux/amd64"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"cloudOperations": false,
|
|
21
|
+
"scope": "Pinned pure-Python wheel dependency closure with explicit selected botocore service data, actual Lambda Python3.12 ARM64 and Python3.13 AMD64 execution. SDK operation/model/endpoints and local signed GET/mode/timestamp/denial/throttle/failure/one-attempt timeout contracts. This is SDK artifact qualification, not generated application safety gates, cloud account state, deployment or all-SDK service compatibility."
|
|
22
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {BrainActivity} from './BrainActivity.jsx';
|
|
2
|
+
import React,{useEffect,useRef,useState,useId} from 'react';
|
|
3
|
+
import {mergeArchitectureActivity,readArchitectureActivity} from './architecture-activity.mjs';
|
|
4
|
+
import {architectureSteps,architectureActivityLabel} from './activity-presentation.mjs';
|
|
5
|
+
import {ChatMessage} from './ChatMessage.jsx';
|
|
6
|
+
import './architecture-activity.css';
|
|
7
|
+
// A view of observed work, never a completion claim about the client's system.
|
|
8
|
+
function TurnActivity({label,latest,steps=[],model,effort,working=false,failed=false,open,onOpenChange,onStop,children}){
|
|
9
|
+
const [expanded,setExpanded]=useState(false),id=useId();const shown=open??expanded;
|
|
10
|
+
const change=value=>{setExpanded(value);onOpenChange?.(value);};
|
|
11
|
+
useEffect(()=>{if(failed)change(true);},[failed]);
|
|
12
|
+
return <div className={'turn-activity'+(failed?' has-error':'')}>
|
|
13
|
+
<div className="turn-activity-row">
|
|
14
|
+
<button type="button" className="turn-activity-toggle" aria-expanded={shown} aria-controls={id} title={[model,effort].filter(Boolean).join(' · ')} onClick={()=>{change(!shown);}}>
|
|
15
|
+
<span aria-hidden="true" className={'turn-state-icon'+(working?' has-brain':'')}>{working?<BrainActivity size={22}/>:failed?'!':'›'}</span>
|
|
16
|
+
<span className="turn-activity-label" role="status" aria-live="polite">{label}</span>{latest&&<span className="turn-latest"> · {latest}</span>}
|
|
17
|
+
<span className="turn-chevron" aria-hidden="true">{shown?'⌄':'›'}</span>
|
|
18
|
+
</button>
|
|
19
|
+
{onStop&&working&&<button type="button" className="turn-inline-action" onClick={onStop}>Stop</button>}
|
|
20
|
+
</div>
|
|
21
|
+
<div id={id} hidden={!shown} className="turn-activity-details">
|
|
22
|
+
{(model||effort)&&<p className="turn-selection">{[model,effort].filter(Boolean).join(' · ')}</p>}
|
|
23
|
+
<ol>{steps.map(step=><li key={step.id} data-step={step.id}>{step.message?<ChatMessage text={step.text}/>:<p>{step.text}</p>}{step.detail&&<small>{step.detail}</small>}</li>)}</ol>
|
|
24
|
+
{children}
|
|
25
|
+
</div>
|
|
26
|
+
</div>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function ArchitectureTurn({turn,projectId,session,active,working,onStop,historyNumber}){
|
|
30
|
+
const [open,setOpen]=useState(false),[events,setEvents]=useState([]),[status,setStatus]=useState(null),[error,setError]=useState('');const cursor=useRef(0),observed=useRef([]);
|
|
31
|
+
useEffect(()=>{
|
|
32
|
+
if((!open&&!active)||!session?.architectureActivityEnabled)return;
|
|
33
|
+
let stopped=false,timer;const controller=new AbortController();
|
|
34
|
+
async function poll(){try{
|
|
35
|
+
const value=await readArchitectureActivity(session,projectId,turn.id,cursor.current,controller.signal);
|
|
36
|
+
if(stopped)return;const merged=mergeArchitectureActivity(observed.current,value.events);observed.current=merged;setEvents(merged);setStatus(value.state);setError('');
|
|
37
|
+
if(value.events.length)cursor.current=value.events.at(-1).sequence;
|
|
38
|
+
if(value.state==='running'||value.events.length===200)timer=setTimeout(poll,value.events.length===200?0:700);
|
|
39
|
+
}catch(e){if(!stopped&&e.name!=='AbortError'){setError(e.status===404?'Details not recorded for this turn.':e.message);if(e.status===404&&working)timer=setTimeout(poll,1000);}}}
|
|
40
|
+
void poll();return()=>{stopped=true;controller.abort();clearTimeout(timer);};
|
|
41
|
+
},[open,active,projectId,turn.id,turn.clientStatus,session?.token,session?.architectureActivityEnabled,working]);
|
|
42
|
+
const steps=architectureSteps(events),label=architectureActivityLabel(turn,status,active),failed=status==='failed'||turn.clientStatus==='failed';
|
|
43
|
+
return <div className="conversation-activity" data-turn={turn.id}><TurnActivity label={historyNumber?'Activity '+historyNumber+' · '+label:label} latest={active?steps.at(-1)?.text:undefined} steps={steps} model={turn.model} effort={turn.effort} working={active} failed={failed} open={open} onOpenChange={setOpen} onStop={active?onStop:undefined}>
|
|
44
|
+
{error&&<p role="status">{error}</p>}
|
|
45
|
+
{!session?.architectureActivityEnabled&&<p>Live details are unavailable from this service. The reply remains in chat.</p>}
|
|
46
|
+
{turn.detailsAvailable===false&&<p>Some activity details were not recorded. The returned response remains in chat.</p>}
|
|
47
|
+
</TurnActivity></div>;
|
|
48
|
+
}
|
|
49
|
+
export function EarlierArchitectureActivity({entries,projectId,session}){
|
|
50
|
+
const [open,setOpen]=useState(false);
|
|
51
|
+
return <details className="legacy-activity" open={open} onToggle={e=>setOpen(e.currentTarget.open)}><summary>{entries.length} earlier {entries.length===1?'turn':'turns'} · activity history</summary>
|
|
52
|
+
{open&&<><p>Recorded before activity was linked to individual replies.</p>{entries.toReversed().map(({turn,number})=><ArchitectureTurn key={projectId+':'+turn.id} turn={turn} projectId={projectId} session={session} active={false} working={false} historyNumber={number}/>)}</>}
|
|
53
|
+
</details>;
|
|
54
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React,{useState,useMemo} from 'react';
|
|
2
|
+
import {architectureWork,workContextIdentity} from './architecture-work.mjs';
|
|
3
|
+
import {artifactWorkProjection} from './artifact-work.mjs';
|
|
4
|
+
const labels={current:'Context current',changed:'Review again',missing:'Missing reference',unreviewed:'Not reviewed'};
|
|
5
|
+
function WorkPanel({project,onChange,busy=false}){
|
|
6
|
+
const [error,setError]=useState('');
|
|
7
|
+
const result=useMemo(()=>{try{return {model:project?architectureWork(project):null,artifacts:project?artifactWorkProjection(project):null};}catch(e){return {error:e.message};}},[project]);
|
|
8
|
+
if(!project)return null;
|
|
9
|
+
if(result.error)return <p role="alert">Work context could not be read: {result.error}</p>;
|
|
10
|
+
const model=result.model;
|
|
11
|
+
const intents=model.entities.filter(e=>e.kind==='intent'&&e.value?.text?.trim()).length,requirements=model.entities.filter(e=>e.kind==='requirement').length;
|
|
12
|
+
const sourceName=id=>model.entities.find(e=>e.id===id)?.title||project.extensions?.architectureWork?.snapshots.findLast(s=>s.ref===id)?.value.title||id;
|
|
13
|
+
const priority={changed:0,missing:0,unreviewed:1,current:2};
|
|
14
|
+
const mappings=model.entities.filter(e=>['responsibility','delivery-unit','interface','implementation','assumption','decision','evidence','requirement','removed'].includes(e.kind)).sort((a,b)=>priority[a.contextStatus]-priority[b.contextStatus]);
|
|
15
|
+
function apply(change){onChange(change,project.id);setError('');}
|
|
16
|
+
async function importProposal(event){const file=event.target.files?.[0];event.target.value='';if(!file)return;try{
|
|
17
|
+
if(file.size>1_500_000)throw Error('Work proposal exceeds its storage limit. Nothing was imported.');
|
|
18
|
+
const value=JSON.parse(await file.text());
|
|
19
|
+
if(value.version!==1||!Array.isArray(value.records)||Object.keys(value).some(k=>!['version','records'].includes(k)))throw Error('Use a version1 work-record proposal.');
|
|
20
|
+
apply({kind:'propose',records:value.records});
|
|
21
|
+
}catch(e){setError(e.message);}}
|
|
22
|
+
return <details className="architecture-work"><summary>Architecture work context · {mappings.filter(e=>e.contextStatus==='changed'||e.contextStatus==='missing').length} need review</summary>
|
|
23
|
+
<p>Requirements, responsibilities, interfaces and implementation mappings share their change context. A current context is a recorded review; it does not establish that an implementation or test passed.</p>
|
|
24
|
+
<p>{intents} intent {intents===1?'source':'sources'} · {requirements} {requirements===1?'requirement':'requirements'}. Free-form engineering updates affect every mapping until reconciled.</p>
|
|
25
|
+
{mappings.length?<ul aria-label="Architecture work mappings">{mappings.map(e=><li key={e.id} data-work-ref={e.id}>
|
|
26
|
+
<strong>{e.title}</strong><span> · {e.kind} · {labels[e.contextStatus]}</span>
|
|
27
|
+
{e.value&&<details><summary>Sources and mapping details</summary><pre>{JSON.stringify({value:e.value,dependsOn:e.dependsOn,review:e.review},null,2)}</pre></details>}
|
|
28
|
+
{e.value?.source&&<small> · {e.value.source} · {e.value.agreement||'recorded'}</small>}
|
|
29
|
+
{e.changedRefs.length>0&&<p>Changed: {e.changedRefs.map(sourceName).join(', ')}</p>}
|
|
30
|
+
{e.missingRefs.length>0&&<p>Missing: {e.missingRefs.map(sourceName).join(', ')}</p>}
|
|
31
|
+
{onChange&&e.contextStatus!=='missing'&&<button disabled={busy} onClick={()=>{try{apply({kind:'review',ref:e.id,expectedContext:workContextIdentity(project,e.id)});}catch(e){setError(e.message);}}}>Record context review: {e.title}</button>}
|
|
32
|
+
</li>)}</ul>:<p>No responsibilities or implementation mappings recorded yet. Engineering can propose them without changing the existing diagram.</p>}
|
|
33
|
+
{onChange&&<label>Import proposed work mappings<input type="file" accept="application/json,.json" disabled={busy} onChange={importProposal}/></label>}
|
|
34
|
+
{result.artifacts.mappings.length>0&&<section aria-label="Linked artifact mappings">
|
|
35
|
+
<h3>Linked artifacts</h3><p>File and context references remain proposed. They do not establish that a test passed or that the implementation meets every requirement.</p>
|
|
36
|
+
<ul>{result.artifacts.mappings.map(m=><li key={m.id} data-artifact-mapping={m.artifactId}>
|
|
37
|
+
<strong>{m.contextStatus==='current'?'Saved context matches':m.contextStatus==='superseded'?'Earlier artifact retained':'Design changed; regenerate mappings'}</strong>
|
|
38
|
+
<span> · {m.records.length} proposed mappings · context revision {m.contextRevision}</span>
|
|
39
|
+
<details><summary>Artifact and file references</summary><pre>{JSON.stringify({artifactId:m.artifactId,artifactSha256:m.artifactSha256,contextSha256:m.contextSha256,files:m.files,changedRefs:m.changedRefs,scope:m.scope},null,2)}</pre></details>
|
|
40
|
+
</li>)}</ul>
|
|
41
|
+
</section>}
|
|
42
|
+
{error&&<p role="alert">{error}</p>}
|
|
43
|
+
</details>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const ArchitectureWorkPanel=React.memo(WorkPanel);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React,{useEffect,useRef,useState} from 'react';
|
|
2
|
+
import {engineeringCall} from './engineering-client.mjs';
|
|
3
|
+
|
|
4
|
+
export function ArtifactChecks({session,projectId,sessionId,artifact,readOnly=false}){
|
|
5
|
+
const [catalog,setCatalog]=useState([]),[available,setAvailable]=useState(false),[checks,setChecks]=useState([]),
|
|
6
|
+
[error,setError]=useState(''),[busy,setBusy]=useState(false);
|
|
7
|
+
const live=useRef(true),locked=useRef(false);
|
|
8
|
+
const payload={projectId,sessionId,artifactId:artifact.id};
|
|
9
|
+
useEffect(()=>{live.current=true;return()=>{live.current=false;};},[]);
|
|
10
|
+
useEffect(()=>{
|
|
11
|
+
const controller=new AbortController();let stopped=false,timer;
|
|
12
|
+
async function poll(){try{
|
|
13
|
+
const [configuration,result]=await Promise.all([
|
|
14
|
+
engineeringCall(session,'validators',{projectId,sessionId},{signal:controller.signal}),
|
|
15
|
+
engineeringCall(session,'validation/list',payload,{signal:controller.signal})]);
|
|
16
|
+
if(stopped)return;
|
|
17
|
+
setCatalog(configuration.validators);setAvailable(configuration.available);setChecks(result.checks);
|
|
18
|
+
}catch(e){if(!stopped&&e.name!=='AbortError')setError(e.message);}
|
|
19
|
+
finally{if(!stopped)timer=setTimeout(poll,1200);}}
|
|
20
|
+
void poll();return()=>{stopped=true;clearTimeout(timer);controller.abort();};
|
|
21
|
+
},[projectId,sessionId,artifact.id,session.token]);
|
|
22
|
+
async function act(action,values){
|
|
23
|
+
if(locked.current)return;locked.current=true;setBusy(true);setError('');
|
|
24
|
+
try{const body=action==='validation/recover'?{projectId,sessionId,...values}:{...payload,...values};const result=await engineeringCall(session,action,body);if(live.current)setChecks(current=>[...current.filter(check=>check.id!==result.id),result]);}
|
|
25
|
+
catch(e){if(live.current)setError(e.message);}finally{locked.current=false;if(live.current)setBusy(false);}
|
|
26
|
+
}
|
|
27
|
+
return <section className="artifact-checks" aria-label="Captured package checks">
|
|
28
|
+
<h3>Package checks</h3><p>Results cover this captured package. Full project acceptance remains pending.</p>
|
|
29
|
+
{!available&&<p>Local checks are unavailable on this server. Your captured package is retained.</p>}
|
|
30
|
+
{!readOnly&&catalog.map(validator=>{
|
|
31
|
+
const previous=checks.filter(check=>check.validatorId===validator.id&&check.contractSha256===validator.contractSha256).at(-1);
|
|
32
|
+
const active=previous&&previous.state!=='finished';
|
|
33
|
+
return <button key={validator.id} disabled={busy||!available||validator.available===false||active} onClick={()=>void act('validation/start',{validatorId:validator.id,retry:!!previous})}>
|
|
34
|
+
{previous?.state==='finished'?'Run again: ':''}{validator.label}{validator.available===false?' · unavailable':''}{active?' · '+previous.state:''}
|
|
35
|
+
</button>;
|
|
36
|
+
})}
|
|
37
|
+
<ol>{checks.map(check=>{
|
|
38
|
+
const definition=catalog.find(validator=>validator.id===check.validatorId),outdated=!definition||(definition.contractSha256!=null&&definition.contractSha256!==check.contractSha256);
|
|
39
|
+
return <li key={check.id}>
|
|
40
|
+
<strong>{check.label} · {check.state==='finished'?check.result?.status||'incomplete':check.state.replaceAll('_',' ')}</strong>
|
|
41
|
+
{outdated&&<p>From a previous check definition; retained as historical evidence.</p>}
|
|
42
|
+
{check.result?.testsReported!=null&&<p>{check.result.testsReported} tests reported · {check.result.skipped||0} skipped</p>}
|
|
43
|
+
{!readOnly&&check.state==='recovery_required'&&<button disabled={busy} onClick={()=>void act('validation/recover',{checkId:check.id})}>Recover check</button>}
|
|
44
|
+
{check.result&&<><details><summary>Check output</summary><pre>{check.result.output||check.result.reason||'No output reported.'}</pre></details></>}
|
|
45
|
+
</li>;
|
|
46
|
+
})}</ol>
|
|
47
|
+
{error&&<p role="alert">{error}</p>}
|
|
48
|
+
</section>;
|
|
49
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React,{useState} from 'react';
|
|
2
|
+
function RequirementCard({requirement,busy,onSave}){
|
|
3
|
+
const [editing,setEditing]=useState(false),[text,setText]=useState(requirement.statement),[error,setError]=useState('');
|
|
4
|
+
async function save(e){e.preventDefault();try{await onSave(requirement.id,text);setEditing(false);setError('');}catch(e){setError(e.message);}}
|
|
5
|
+
return <article className="block-requirement" aria-label={`Requirement ${requirement.id}`}>
|
|
6
|
+
{editing?<form onSubmit={save}><label>Requirement<textarea aria-label="Requirement text" maxLength={1000} value={text} onChange={e=>setText(e.target.value)}/></label><div className="block-review-actions"><button className="btn primary" disabled={busy||!text.trim()}>Save & re-evaluate</button><button type="button" className="btn ghost" disabled={busy} onClick={()=>setEditing(false)}>Cancel</button></div>{error&&<p role="alert">{error}</p>}</form>:<><p>{requirement.statement}</p><button className="link" disabled={busy} onClick={()=>{setText(requirement.statement);setEditing(true);}}>Edit requirement</button></>}
|
|
7
|
+
{requirement.measure&&<small>Acceptance target: {requirement.measure.metric} {requirement.measure.op} {String(requirement.measure.target)} {requirement.measure.unit}</small>}
|
|
8
|
+
</article>;
|
|
9
|
+
}
|
|
10
|
+
export function BlockRequirements({project,nodeId,busy,onSave}){
|
|
11
|
+
const needs=(project.needs||[]).filter(r=>r.links?.includes(nodeId));
|
|
12
|
+
return <section className="block-requirements" aria-label="Block requirements"><strong>Requirements for this block</strong>{needs.length?needs.map(r=><RequirementCard key={r.id} requirement={r} busy={busy} onSave={onSave}/>):<p className="muted">No requirements linked yet.</p>}<small>Saving updates local checks and requests an Architect review when connected. Linked blocks will need review again.</small></section>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React,{useId} from 'react';
|
|
2
|
+
// Brain artwork supplied by the user. Crop the wordmark for legibility at icon size.
|
|
3
|
+
export function BrainActivity({size=24,active=true}){
|
|
4
|
+
const mask=useId();
|
|
5
|
+
return <svg className={`brain-activity${active?' is-active':''}`} width={size} height={size} viewBox="-150 -135 300 255" aria-hidden="true" focusable="false">
|
|
6
|
+
<defs><mask id={mask} maskUnits="userSpaceOnUse" x="-200" y="-200" width="400" height="400"><rect x="-200" y="-200" width="400" height="400" fill="#fff"/>{[false,true].map(mirror=><path key={String(mirror)} d="M124 -31 Q98 -30 90 -54 M79 -88 Q72 -66 50 -60" transform={mirror?'scale(-1 1)':undefined} stroke="#000" strokeWidth="9" strokeLinecap="round" fill="none"/>)}</mask></defs>
|
|
7
|
+
<g mask={`url(#${mask})`} fill="#F3A2B4">{[false,true].map(mirror=><path key={String(mirror)} d="M7 -104 A41.2 41.2 0 0 1 78.8 -87.95 A40.71 40.71 0 0 1 124.2 -31.16 A38 38 0 0 1 116.93 36.3 A42.22 42.22 0 0 1 60.09 85.83 A29.75 29.75 0 0 1 7 84 Z" transform={mirror?'scale(-1 1)':undefined}/>)}</g>
|
|
8
|
+
{[-47,47].map(x=><g key={x}><circle cx={x} cy="26" r="35" fill="#F3F7F7" stroke="#101314" strokeWidth="12"/><circle cx={x+5} cy="21" r="10.5" fill="#101314"/></g>)}
|
|
9
|
+
<path d="M-12 18 Q0 0 12 18" fill="none" stroke="#101314" strokeWidth="12" strokeLinecap="round"/>
|
|
10
|
+
</svg>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
// Small, non-HTML Markdown renderer: no remote images, raw HTML or executable URLs.
|
|
3
|
+
function inline(text){return text.split(/(\*\*[^*]+\*\*|`[^`]+`|\[[^\]]+\]\(https?:\/\/[^\s)]+\))/g).map((part,i)=>{
|
|
4
|
+
if(part.startsWith('**')&&part.endsWith('**'))return <strong key={i}>{part.slice(2,-2)}</strong>;
|
|
5
|
+
if(part.startsWith('`')&&part.endsWith('`'))return <code key={i}>{part.slice(1,-1)}</code>;
|
|
6
|
+
const link=part.match(/^\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)$/);if(link)return <a key={i} href={link[2]} target="_blank" rel="noopener noreferrer">{link[1]}</a>;
|
|
7
|
+
return part;
|
|
8
|
+
});}
|
|
9
|
+
export function ChatMessage({text=''}){
|
|
10
|
+
const lines=text.split('\n'),blocks=[];let i=0;
|
|
11
|
+
while(i<lines.length){
|
|
12
|
+
if(!lines[i].trim()){i++;continue;}
|
|
13
|
+
if(lines[i].startsWith('```')){const code=[];i++;while(i<lines.length&&!lines[i].startsWith('```'))code.push(lines[i++]);i++;blocks.push(<pre key={blocks.length}><code>{code.join('\n')}</code></pre>);continue;}
|
|
14
|
+
const heading=lines[i].match(/^#{1,6}\s+(.+)$/);if(heading){blocks.push(<h4 key={blocks.length}>{inline(heading[1])}</h4>);i++;continue;}
|
|
15
|
+
const list=lines[i].match(/^(?:[-*]|\d+[.)])\s+/);if(list){const ordered=/^\d/.test(list[0]),items=[];while(i<lines.length&&/^(?:[-*]|\d+[.)])\s+/.test(lines[i]))items.push(<li key={items.length}>{inline(lines[i++].replace(/^(?:[-*]|\d+[.)])\s+/,''))}</li>);blocks.push(ordered?<ol key={blocks.length}>{items}</ol>:<ul key={blocks.length}>{items}</ul>);continue;}
|
|
16
|
+
const paragraph=[];while(i<lines.length&&lines[i].trim()&&!/^(?:```|#{1,6}\s|[-*]\s|\d+[.)]\s)/.test(lines[i]))paragraph.push(lines[i++]);blocks.push(<p key={blocks.length}>{paragraph.map((line,j)=><React.Fragment key={j}>{j>0&&<br/>}{inline(line)}</React.Fragment>)}</p>);
|
|
17
|
+
}
|
|
18
|
+
return <div className="chat-markdown">{blocks}</div>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export function ChatResizeHandle({width,onChange}){
|
|
3
|
+
const max=()=>Math.max(320,Math.min(900,window.innerWidth-360));
|
|
4
|
+
const resize=value=>onChange(Math.round(Math.max(320,Math.min(max(),value))));
|
|
5
|
+
return <div className="chat-resize-handle" role="separator" aria-label="Resize chat panel" aria-orientation="vertical" aria-valuemin={320} aria-valuemax={max()} aria-valuenow={width} tabIndex={0} title="Drag to resize chat. Arrow keys resize; double-click resets." onDoubleClick={()=>resize(360)} onKeyDown={e=>{if(['ArrowLeft','ArrowRight','Home','End'].includes(e.key)){e.preventDefault();resize(e.key==='Home'?320:e.key==='End'?max():width+(e.key==='ArrowLeft'?32:-32));}}} onPointerDown={e=>{if(e.button!==0)return;e.preventDefault();e.currentTarget.setPointerCapture(e.pointerId);}} onPointerMove={e=>{if(e.currentTarget.hasPointerCapture(e.pointerId))resize(e.currentTarget.closest('.app').getBoundingClientRect().right-e.clientX);}} onPointerUp={e=>{if(e.currentTarget.hasPointerCapture(e.pointerId))e.currentTarget.releasePointerCapture(e.pointerId);}}/>;
|
|
6
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
// React escapes every token; previews never inject HTML or execute source.
|
|
3
|
+
export function CodePreview({content,name='',className=''}){
|
|
4
|
+
const source=typeof content==='string'?content:String(content);
|
|
5
|
+
const pattern=/("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\/\/[^\n]*|#[^\n]*|\b(?:true|false|null|resource|variable|output|provider|terraform|module|locals|data)\b|\b\d+(?:\.\d+)?\b)/g;
|
|
6
|
+
const parts=source.split(pattern);
|
|
7
|
+
return <pre className={`code-preview ${className}`} aria-label={name||'Code preview'}><code>{parts.map((text,i)=>i%2?<span key={i} className={/^['"]/.test(text)?(/^\s*:/.test(parts[i+1]||'')?'code-key':'code-string'):/^(\/\/|#)/.test(text)?'code-comment':/^\d/.test(text)?'code-number':'code-keyword'}>{text}</span>:text)}</code></pre>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React,{useState} from 'react';
|
|
2
|
+
import {CheckCircle2, CircleHelp, Circle, RefreshCw, ChevronLeft, ChevronRight, MessageCircle, Plus, AlertCircle} from 'lucide-react';
|
|
3
|
+
import {reviewIssueLabel} from './component-review.mjs';
|
|
4
|
+
function QuestionAnswer({question,busy,onResolve}){
|
|
5
|
+
const [answer,setAnswer]=useState('');
|
|
6
|
+
return <details><summary>Record answer</summary><form onSubmit={e=>{e.preventDefault();if(answer.trim())onResolve(question.id,answer.trim());}}><label>Answer<textarea aria-label={`Answer: ${question.text}`} maxLength={2000} value={answer} onChange={e=>setAnswer(e.target.value)}/></label><button className="btn ghost" disabled={busy||!answer.trim()}>Save answer</button></form></details>;
|
|
7
|
+
}
|
|
8
|
+
function DetailAnswer({question,busy,onSave}){
|
|
9
|
+
const [answer,setAnswer]=useState('');const ownership=question.id==='detail-Ownership recorded',region=question.id==='detail-Cloud region selected';
|
|
10
|
+
return <form className="block-question-form" onSubmit={e=>{e.preventDefault();if(answer.trim())onSave(ownership?{origin:answer}:region?{config:{region:answer.trim()}}:{description:answer.trim()});}}><label>{ownership?'System ownership':region?'Cloud region':'Block responsibility'}{ownership?<select aria-label="System ownership" value={answer} onChange={e=>setAnswer(e.target.value)}><option value="">Choose…</option><option value="existing">Existing system</option><option value="proposed">Proposed component</option></select>:<textarea aria-label={region?'Cloud region answer':'Block responsibility answer'} maxLength={region?100:16000} value={answer} onChange={e=>setAnswer(e.target.value)}/>}</label><button className="btn ghost" disabled={busy||!answer.trim()}>Save detail</button></form>;
|
|
11
|
+
}
|
|
12
|
+
export function ReviewBadge({item,onClick}){
|
|
13
|
+
const Icon={reviewed:CheckCircle2,questions:CircleHelp,issues:AlertCircle,ready:Circle,changed:RefreshCw}[item.status];
|
|
14
|
+
const label=item.issues.length?reviewIssueLabel(item.issues):item.statusLabel,tone=item.status==='issues'?'questions':item.status;
|
|
15
|
+
return onClick?<button className={`block-review-badge ${tone} nodrag`} aria-label={`Review ${item.label}: ${label}`} title={`${label} · design review, not runtime validation`} onClick={e=>{e.stopPropagation();onClick();}}><Icon size={13}/>{label}</button>:<span className={`block-review-badge ${tone}`}><Icon size={14}/>{label}</span>;
|
|
16
|
+
}
|
|
17
|
+
export function ComponentReview({item,items,busy,onOpen,onConfirm,onDiscuss,onQuestion,onResolve,onDetailAnswer}){
|
|
18
|
+
const [adding,setAdding]=useState(false),[question,setQuestion]=useState('');const index=items.findIndex(r=>r.id===item.id);
|
|
19
|
+
return <section className="component-review" aria-label="Block design review">
|
|
20
|
+
<div className="block-review-heading"><strong>Block {index+1} of {items.length}</strong><ReviewBadge item={item}/></div>
|
|
21
|
+
<div className="block-review-progress"><progress aria-label="Blocks reviewed" max={items.length} value={items.filter(r=>r.status==='reviewed').length}/><small>{items.filter(r=>r.status==='reviewed').length} reviewed</small></div>
|
|
22
|
+
{item.status==='changed'&&<p>The block or its context changed. Check it again.</p>}
|
|
23
|
+
{item.architectNote&&<div className="block-architect-note"><strong>{item.architectNoteCurrent?'Architect’s review':'Previous review · context changed'}</strong><p>{item.architectNote}</p></div>}
|
|
24
|
+
<ul className="block-review-checks">{item.checks.map(c=><li key={c.label} className={c.passed?'complete':'incomplete'}>{c.passed?<CheckCircle2 size={14}/>:<CircleHelp size={14}/>} {c.label}</li>)}</ul>
|
|
25
|
+
{!!item.issues.length&&<ul className="block-review-questions">{item.issues.map(q=><li key={q.id}><strong>{q.kind==='finding'?'Design issue':'Question'}</strong><span>{q.text}</span>{q.action&&<small>Suggested next step: {q.action}</small>}{q.kind==='question'&&<QuestionAnswer question={q} busy={busy} onResolve={onResolve}/>} {q.kind==='detail'&&<DetailAnswer question={q} busy={busy} onSave={onDetailAnswer}/>} {q.kind==='finding'&&<button className="link" disabled={busy} onClick={()=>onDiscuss(q)}>Ask Architect to plan this fix</button>}</li>)}</ul>}
|
|
26
|
+
<div className="block-review-actions"><button className="btn primary" disabled={busy||item.issues.length>0||item.status==='reviewed'} onClick={onConfirm}><CheckCircle2 size={14}/>{item.status==='reviewed'?'Design reviewed':'Looks good'}</button><button className="btn ghost" disabled={busy} onClick={onDiscuss}><MessageCircle size={14}/>Ask Architect</button><button className="btn ghost" disabled={busy} onClick={()=>setAdding(!adding)}><Plus size={14}/>Question</button></div>
|
|
27
|
+
{adding&&<form className="block-question-form" onSubmit={e=>{e.preventDefault();if(question.trim()){onQuestion(question.trim());setQuestion('');setAdding(false);}}}><label>Question about this block<textarea aria-label="Question about this block" maxLength={1000} value={question} onChange={e=>setQuestion(e.target.value)} autoFocus/></label><button className="btn" disabled={busy||!question.trim()}>Save question</button></form>}
|
|
28
|
+
<small className="block-review-boundary">Design review only. Implementation and runtime checks are separate.</small>
|
|
29
|
+
<nav className="block-review-navigation" aria-label="Review blocks one by one"><button className="btn ghost" disabled={index===0} onClick={()=>onOpen(items[index-1].id)}><ChevronLeft size={14}/>Previous</button><button className="btn ghost" disabled={index===items.length-1} onClick={()=>onOpen(items[index+1].id)}>Next block<ChevronRight size={14}/></button></nav>
|
|
30
|
+
</section>;
|
|
31
|
+
}
|