ltcai 11.5.2 → 11.7.0
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/README.md +93 -148
- package/bin/ltcai.js +234 -24
- package/docs/CHANGELOG.md +119 -0
- package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
- package/docs/DEVELOPMENT.md +8 -6
- package/docs/ENTERPRISE.md +2 -1
- package/docs/MULTI_AGENT_RUNTIME.md +12 -5
- package/docs/ONBOARDING.md +1 -1
- package/docs/OPERATIONS.md +6 -3
- package/docs/REALTIME_COLLABORATION.md +1 -1
- package/docs/TRUST_MODEL.md +1 -1
- package/docs/WHY_LATTICE.md +1 -1
- package/docs/WORKFLOW_DESIGNER.md +3 -2
- package/docs/kg-schema.md +1 -1
- package/docs/v11.6.0_ONE_DOOR_PLAN.md +170 -0
- package/lattice_brain/__init__.py +42 -79
- package/lattice_brain/graph/__init__.py +9 -24
- package/lattice_brain/graph/_kg_common/__init__.py +13 -24
- package/lattice_brain/ingestion/__init__.py +19 -58
- package/lattice_brain/ingestion/pipeline.py +20 -398
- package/lattice_brain/multimodal/__init__.py +7 -18
- package/lattice_brain/multimodal/images.py +6 -264
- package/lattice_brain/multimodal/video.py +8 -247
- package/lattice_brain/runtime/__init__.py +8 -79
- package/lattice_brain/runtime/hooks.py +22 -584
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/agent_worker_seam.py +7 -80
- package/latticeai/api/health.py +6 -20
- package/latticeai/api/local_files.py +16 -613
- package/latticeai/api/models.py +12 -87
- package/latticeai/api/search.py +17 -255
- package/latticeai/api/tools.py +69 -750
- package/latticeai/api/voice_capture.py +8 -70
- package/latticeai/api/worker_compute.py +842 -0
- package/latticeai/api/worker_seams.py +216 -0
- package/latticeai/app_factory.py +23 -232
- package/latticeai/cli/entrypoint.py +36 -249
- package/latticeai/core/agent_permission.py +16 -91
- package/latticeai/core/messages.py +89 -531
- package/latticeai/runtime/access_runtime.py +0 -14
- package/latticeai/runtime/bootstrap.py +10 -21
- package/latticeai/runtime/brain_runtime.py +35 -43
- package/latticeai/runtime/build_phases/__init__.py +21 -37
- package/latticeai/runtime/build_phases/features.py +99 -389
- package/latticeai/runtime/build_phases/foundation.py +82 -392
- package/latticeai/runtime/build_phases/web.py +91 -408
- package/latticeai/runtime/build_phases/worker_profile.py +244 -0
- package/latticeai/runtime/lifespan_runtime.py +7 -16
- package/latticeai/runtime/platform_services_runtime.py +1 -15
- package/latticeai/runtime/runtime_context.py +13 -130
- package/latticeai/runtime/security_runtime.py +10 -103
- package/latticeai/services/architecture_readiness.py +82 -43
- package/latticeai/services/model_runtime/__init__.py +2 -11
- package/latticeai/services/model_runtime/service.py +4 -28
- package/latticeai/services/p_reinforce.py +10 -261
- package/latticeai/services/product_readiness.py +31 -38
- package/latticeai/services/search_service.py +37 -795
- package/latticeai/services/tool_dispatch.py +30 -386
- package/latticeai/services/voice_capture.py +13 -107
- package/latticeai/tools/__init__.py +22 -49
- package/latticeai/tools/commands.py +0 -163
- package/latticeai/tools/computer.py +0 -39
- package/latticeai/tools/documents.py +1 -134
- package/latticeai/tools/filesystem.py +1 -247
- package/latticeai/tools/knowledge.py +1 -52
- package/latticeai/tools/local_files.py +0 -20
- package/latticeai/worker_app.py +75 -0
- package/package.json +2 -3
- package/requirements.txt +0 -5
- package/scripts/agent_eval.py +16 -28
- package/scripts/brain_quality_eval.py +20 -183
- package/scripts/bump_version.py +5 -5
- package/scripts/check_current_release_docs.mjs +7 -4
- package/scripts/check_openapi_drift.mjs +10 -0
- package/scripts/check_server_i18n.mjs +2 -18
- package/scripts/compose_openapi.py +377 -0
- package/scripts/export_openapi.py +32 -4
- package/scripts/gen_messages_catalog_fixture.py +302 -0
- package/scripts/gen_openapi_fragments.py +365 -0
- package/scripts/gen_redact_fixture.py +196 -0
- package/scripts/gen_worker_allowlist_fixture.py +115 -0
- package/scripts/generate_agent_parity_fixtures.py +33 -14
- package/scripts/openapi_route_families.json +2161 -0
- package/scripts/release_screen_claims.json +54 -0
- package/scripts/run_integration_tests.mjs +134 -29
- package/scripts/run_sidecar_e2e.mjs +104 -11
- package/scripts/wheel_smoke.py +32 -22
- package/src-tauri/Cargo.lock +375 -9
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/src/backend.rs +151 -45
- package/src-tauri/src/main.rs +18 -18
- package/src-tauri/src/topology.rs +58 -88
- package/src-tauri/tauri.conf.json +1 -2
- package/static/app/asset-manifest.json +41 -41
- package/static/app/assets/{Act-DcQizkl1.js → Act-BPcVAbOL.js} +1 -1
- package/static/app/assets/AdminConsole-Bw1ATQL0.js +1 -0
- package/static/app/assets/{Brain-3VCSHFcn.js → Brain-CT92Kos0.js} +2 -2
- package/static/app/assets/{BrainHome-Qm8eaztx.js → BrainHome-CFBkt1K_.js} +1 -1
- package/static/app/assets/{BrainSignals-DS9BtKOW.js → BrainSignals-ReLWF2H8.js} +1 -1
- package/static/app/assets/Capture-BsTokYkk.js +1 -0
- package/static/app/assets/{Chronicle-BGvuAchH.js → Chronicle-B6f0T9id.js} +1 -1
- package/static/app/assets/{CommandPalette-Bqhm0Urn.js → CommandPalette-CuvjTv1u.js} +1 -1
- package/static/app/assets/{Library-BV6NnF0a.js → Library-BGJbG9Hd.js} +1 -1
- package/static/app/assets/{LivingBrain-GzenJchP.js → LivingBrain-DGYK_Jsa.js} +1 -1
- package/static/app/assets/{ProductFlow-DEP6-vML.js → ProductFlow-DXBC6brE.js} +1 -1
- package/static/app/assets/{ReviewCard-CNZ7XjWG.js → ReviewCard-HXRle3qq.js} +2 -2
- package/static/app/assets/System-CMHSO9qM.js +1 -0
- package/static/app/assets/arrow-left-BfmkskWx.js +1 -0
- package/static/app/assets/{bot-B_K1Tdmw.js → bot-Cn8bWRuq.js} +1 -1
- package/static/app/assets/{brain-DWyaV1L1.js → brain-CQJberbE.js} +1 -1
- package/static/app/assets/{button-aTn4s84A.js → button-Ct9f2_oT.js} +1 -1
- package/static/app/assets/circle-check-DruOxB-4.js +1 -0
- package/static/app/assets/{circle-pause-xKgeGXkT.js → circle-pause-CmzC_apg.js} +1 -1
- package/static/app/assets/{circle-play-DkT6tYPX.js → circle-play-D8mW2aQ7.js} +1 -1
- package/static/app/assets/{cpu-85xYObUC.js → cpu-DZcdd0PZ.js} +1 -1
- package/static/app/assets/{download-B5Fm7YXo.js → download-bv1KEPGQ.js} +1 -1
- package/static/app/assets/{folder-open-kk2Xa52u.js → folder-open-d-Pip5gr.js} +1 -1
- package/static/app/assets/{hard-drive-DkA3zBW_.js → hard-drive-D20iavUb.js} +1 -1
- package/static/app/assets/index-D9x-kSNy.css +2 -0
- package/static/app/assets/{index-BMPdTmlY.js → index-Do83hDzJ.js} +3 -3
- package/static/app/assets/{input-B0nRf2jO.js → input-BLXVNmj1.js} +1 -1
- package/static/app/assets/{link-2-Dwb4gnTc.js → link-2-BPJOFlAy.js} +1 -1
- package/static/app/assets/{permissionCopy-CQDUBrOZ.js → permissionCopy-ChdJd493.js} +1 -1
- package/static/app/assets/primitives-Cv5tbZBY.js +1 -0
- package/static/app/assets/search-CT9aho2j.js +1 -0
- package/static/app/assets/{share-2-BsrxFglO.js → share-2-YNX_NtMU.js} +1 -1
- package/static/app/assets/{shield-alert-5BStfp2_.js → shield-alert-DuQ3zrVL.js} +1 -1
- package/static/app/assets/{textarea-Cg8IUA-k.js → textarea-DqwLnli4.js} +1 -1
- package/static/app/assets/{useFocusTrap-CYKvE46M.js → useFocusTrap-ZVI98jaW.js} +1 -1
- package/static/app/assets/{useMutation-CSn9t1op.js → useMutation-CVC4qv_D.js} +1 -1
- package/static/app/assets/{useQuery-CY2OI2uy.js → useQuery-C7BeG4HU.js} +1 -1
- package/static/app/assets/{utils-Ddol2RWD.js → utils-CiFtIdZq.js} +1 -1
- package/static/app/assets/{workspace-BqDwOz_p.js → workspace-DQz9vIId.js} +1 -1
- package/static/app/index.html +4 -4
- package/static/sw.js +1 -1
- package/lattice_brain/archive.py +0 -522
- package/lattice_brain/context.py +0 -325
- package/lattice_brain/conversations.py +0 -382
- package/lattice_brain/core.py +0 -82
- package/lattice_brain/graph/_kg_contract.py +0 -249
- package/lattice_brain/graph/curator.py +0 -676
- package/lattice_brain/graph/discovery.py +0 -595
- package/lattice_brain/graph/discovery_index/__init__.py +0 -35
- package/lattice_brain/graph/discovery_index/cleanup.py +0 -182
- package/lattice_brain/graph/discovery_index/extract.py +0 -137
- package/lattice_brain/graph/discovery_index/scan.py +0 -411
- package/lattice_brain/graph/discovery_index/upsert.py +0 -495
- package/lattice_brain/graph/documents.py +0 -380
- package/lattice_brain/graph/fusion.py +0 -395
- package/lattice_brain/graph/identity.py +0 -175
- package/lattice_brain/graph/image_vectors.py +0 -230
- package/lattice_brain/graph/ingest.py +0 -829
- package/lattice_brain/graph/network.py +0 -205
- package/lattice_brain/graph/proactive.py +0 -724
- package/lattice_brain/graph/projection/__init__.py +0 -42
- package/lattice_brain/graph/projection/curation.py +0 -500
- package/lattice_brain/graph/projection/v2_schema.py +0 -518
- package/lattice_brain/graph/provenance.py +0 -524
- package/lattice_brain/graph/rerank.py +0 -163
- package/lattice_brain/graph/retrieval/__init__.py +0 -54
- package/lattice_brain/graph/retrieval/context.py +0 -197
- package/lattice_brain/graph/retrieval/graph_view.py +0 -319
- package/lattice_brain/graph/retrieval/hybrid.py +0 -488
- package/lattice_brain/graph/retrieval/maintenance.py +0 -121
- package/lattice_brain/graph/retrieval/signals.py +0 -95
- package/lattice_brain/graph/retrieval_docgen.py +0 -253
- package/lattice_brain/graph/retrieval_policy.py +0 -180
- package/lattice_brain/graph/retrieval_reads.py +0 -769
- package/lattice_brain/graph/retrieval_vector/__init__.py +0 -42
- package/lattice_brain/graph/retrieval_vector/fingerprint.py +0 -97
- package/lattice_brain/graph/retrieval_vector/indexing.py +0 -347
- package/lattice_brain/graph/retrieval_vector/search.py +0 -560
- package/lattice_brain/graph/retrieval_vector/status.py +0 -374
- package/lattice_brain/graph/schema.py +0 -792
- package/lattice_brain/graph/store.py +0 -268
- package/lattice_brain/graph/vector_index/__init__.py +0 -85
- package/lattice_brain/graph/vector_index/base.py +0 -167
- package/lattice_brain/graph/vector_index/brute_force.py +0 -110
- package/lattice_brain/graph/vector_index/hnsw.py +0 -290
- package/lattice_brain/graph/vector_index/jobs.py +0 -287
- package/lattice_brain/graph/vector_index/quantized.py +0 -148
- package/lattice_brain/graph/vector_index/selector.py +0 -161
- package/lattice_brain/graph/write_master.py +0 -308
- package/lattice_brain/ingestion/_contract.py +0 -90
- package/lattice_brain/ingestion/folder_scan.py +0 -57
- package/lattice_brain/ingestion/folders.py +0 -258
- package/lattice_brain/ingestion/jobs_api.py +0 -107
- package/lattice_brain/ingestion/routing.py +0 -295
- package/lattice_brain/ingestion_jobs.py +0 -380
- package/lattice_brain/memory.py +0 -75
- package/lattice_brain/portability/__init__.py +0 -90
- package/lattice_brain/portability/_contract.py +0 -42
- package/lattice_brain/portability/backups.py +0 -338
- package/lattice_brain/portability/bundles.py +0 -136
- package/lattice_brain/portability/constants.py +0 -93
- package/lattice_brain/portability/fsops.py +0 -138
- package/lattice_brain/portability/service.py +0 -41
- package/lattice_brain/portability/sharing.py +0 -710
- package/lattice_brain/quality.py +0 -543
- package/lattice_brain/retrieval_benchmark_fixtures.py +0 -92
- package/lattice_brain/runtime/agent_runtime.py +0 -859
- package/lattice_brain/runtime/contracts.py +0 -460
- package/lattice_brain/runtime/multi_agent.py +0 -942
- package/lattice_brain/runtime/statuses.py +0 -10
- package/lattice_brain/sealed_box.py +0 -240
- package/lattice_brain/self_model.py +0 -675
- package/lattice_brain/sensitivity.py +0 -94
- package/lattice_brain/storage/__init__.py +0 -22
- package/lattice_brain/storage/base.py +0 -100
- package/lattice_brain/storage/docker.py +0 -105
- package/lattice_brain/storage/factory.py +0 -31
- package/lattice_brain/storage/migration.py +0 -191
- package/lattice_brain/storage/postgres.py +0 -123
- package/lattice_brain/storage/sqlite.py +0 -143
- package/lattice_brain/synthesis.py +0 -824
- package/lattice_brain/workflow.py +0 -497
- package/latticeai/api/admin.py +0 -471
- package/latticeai/api/agent_registry.py +0 -105
- package/latticeai/api/agents.py +0 -228
- package/latticeai/api/auth.py +0 -383
- package/latticeai/api/automation_intelligence.py +0 -401
- package/latticeai/api/brain_intelligence.py +0 -199
- package/latticeai/api/browser.py +0 -493
- package/latticeai/api/change_proposals.py +0 -89
- package/latticeai/api/chat.py +0 -572
- package/latticeai/api/chat_agent_http.py +0 -892
- package/latticeai/api/chat_contracts.py +0 -73
- package/latticeai/api/chat_documents.py +0 -276
- package/latticeai/api/chat_helpers.py +0 -460
- package/latticeai/api/chat_history.py +0 -101
- package/latticeai/api/chat_hybrid.py +0 -113
- package/latticeai/api/chat_intents.py +0 -646
- package/latticeai/api/chat_stream.py +0 -216
- package/latticeai/api/chronicle.py +0 -63
- package/latticeai/api/command_center.py +0 -51
- package/latticeai/api/computer_use.py +0 -474
- package/latticeai/api/evidence_actions.py +0 -48
- package/latticeai/api/features.py +0 -70
- package/latticeai/api/funnel_metrics.py +0 -31
- package/latticeai/api/garden.py +0 -34
- package/latticeai/api/hooks.py +0 -165
- package/latticeai/api/index_jobs.py +0 -145
- package/latticeai/api/invitations.py +0 -100
- package/latticeai/api/knowledge_graph.py +0 -536
- package/latticeai/api/marketplace.py +0 -105
- package/latticeai/api/mcp.py +0 -482
- package/latticeai/api/memory.py +0 -270
- package/latticeai/api/network.py +0 -81
- package/latticeai/api/network_boundary.py +0 -225
- package/latticeai/api/permission_mode.py +0 -61
- package/latticeai/api/permissions.py +0 -436
- package/latticeai/api/plugins.py +0 -126
- package/latticeai/api/portability.py +0 -391
- package/latticeai/api/project_sessions.py +0 -114
- package/latticeai/api/realtime.py +0 -118
- package/latticeai/api/review_queue.py +0 -364
- package/latticeai/api/security_dashboard.py +0 -604
- package/latticeai/api/setup.py +0 -319
- package/latticeai/api/static_routes.py +0 -354
- package/latticeai/api/ui_redirects.py +0 -26
- package/latticeai/api/workflow_designer.py +0 -394
- package/latticeai/api/workspace.py +0 -856
- package/latticeai/api/workspace_scope.py +0 -125
- package/latticeai/core/agent/__init__.py +0 -93
- package/latticeai/core/agent/_contract.py +0 -79
- package/latticeai/core/agent/context.py +0 -57
- package/latticeai/core/agent/deps.py +0 -125
- package/latticeai/core/agent/execution.py +0 -622
- package/latticeai/core/agent/planning.py +0 -145
- package/latticeai/core/agent/recovery.py +0 -157
- package/latticeai/core/agent/runtime.py +0 -210
- package/latticeai/core/agent/verification.py +0 -231
- package/latticeai/core/agent_eval.py +0 -739
- package/latticeai/core/agent_helpers.py +0 -493
- package/latticeai/core/agent_profiles.py +0 -110
- package/latticeai/core/agent_prompts.py +0 -171
- package/latticeai/core/agent_registry.py +0 -232
- package/latticeai/core/agent_state.py +0 -41
- package/latticeai/core/agent_trace.py +0 -104
- package/latticeai/core/artifact_ledger.py +0 -109
- package/latticeai/core/audit.py +0 -260
- package/latticeai/core/builtin_hooks.py +0 -105
- package/latticeai/core/context_builder.py +0 -394
- package/latticeai/core/document_generator.py +0 -103
- package/latticeai/core/enterprise.py +0 -154
- package/latticeai/core/enterprise_admin.py +0 -158
- package/latticeai/core/file_generation/__init__.py +0 -115
- package/latticeai/core/file_generation/bundles.py +0 -76
- package/latticeai/core/file_generation/extraction.py +0 -154
- package/latticeai/core/file_generation/inference.py +0 -235
- package/latticeai/core/file_generation/orchestration.py +0 -152
- package/latticeai/core/file_generation/prompting.py +0 -117
- package/latticeai/core/file_generation/repair.py +0 -114
- package/latticeai/core/file_generation/sanitize.py +0 -61
- package/latticeai/core/file_generation/validation.py +0 -201
- package/latticeai/core/invitations.py +0 -132
- package/latticeai/core/legacy_compatibility.py +0 -243
- package/latticeai/core/logging_safety.py +0 -46
- package/latticeai/core/marketplace.py +0 -293
- package/latticeai/core/mcp_catalog.py +0 -452
- package/latticeai/core/mcp_registry.py +0 -506
- package/latticeai/core/network_boundary.py +0 -168
- package/latticeai/core/oidc.py +0 -208
- package/latticeai/core/plugins.py +0 -432
- package/latticeai/core/product_hardening.py +0 -218
- package/latticeai/core/project_sessions.py +0 -337
- package/latticeai/core/realtime.py +0 -238
- package/latticeai/core/run_explain.py +0 -426
- package/latticeai/core/run_store.py +0 -252
- package/latticeai/core/timezones.py +0 -80
- package/latticeai/core/workspace_computer_memory.py +0 -84
- package/latticeai/core/workspace_graph_trace.py +0 -155
- package/latticeai/core/workspace_indexing.py +0 -102
- package/latticeai/core/workspace_memory.py +0 -77
- package/latticeai/core/workspace_onboarding.py +0 -104
- package/latticeai/core/workspace_os.py +0 -978
- package/latticeai/core/workspace_os_constants.py +0 -126
- package/latticeai/core/workspace_os_state.py +0 -180
- package/latticeai/core/workspace_os_utils.py +0 -103
- package/latticeai/core/workspace_permissions.py +0 -101
- package/latticeai/core/workspace_plugins.py +0 -97
- package/latticeai/core/workspace_relationships.py +0 -99
- package/latticeai/core/workspace_reorganization.py +0 -335
- package/latticeai/core/workspace_review_items.py +0 -112
- package/latticeai/core/workspace_runs.py +0 -726
- package/latticeai/core/workspace_skills.py +0 -109
- package/latticeai/core/workspace_snapshots.py +0 -198
- package/latticeai/core/workspace_timeline.py +0 -110
- package/latticeai/integrations/__init__.py +0 -0
- package/latticeai/integrations/telegram_bot/__init__.py +0 -123
- package/latticeai/integrations/telegram_bot/__main__.py +0 -17
- package/latticeai/integrations/telegram_bot/config.py +0 -86
- package/latticeai/integrations/telegram_bot/dispatch.py +0 -311
- package/latticeai/integrations/telegram_bot/flows.py +0 -478
- package/latticeai/integrations/telegram_bot/helpers.py +0 -322
- package/latticeai/integrations/telegram_bot/screens.py +0 -394
- package/latticeai/runtime/audit_runtime.py +0 -76
- package/latticeai/runtime/automation_runtime.py +0 -81
- package/latticeai/runtime/chat_wiring.py +0 -141
- package/latticeai/runtime/context_runtime.py +0 -66
- package/latticeai/runtime/feature_toggle_wiring.py +0 -157
- package/latticeai/runtime/history_runtime.py +0 -163
- package/latticeai/runtime/history_writer.py +0 -138
- package/latticeai/runtime/hooks_runtime.py +0 -77
- package/latticeai/runtime/model_wiring.py +0 -68
- package/latticeai/runtime/namespace_runtime.py +0 -163
- package/latticeai/runtime/network_boundary_wiring.py +0 -117
- package/latticeai/runtime/network_config_runtime.py +0 -56
- package/latticeai/runtime/permission_mode_wiring.py +0 -112
- package/latticeai/runtime/persistence_runtime.py +0 -159
- package/latticeai/runtime/platform_runtime_wiring.py +0 -89
- package/latticeai/runtime/review_wiring.py +0 -42
- package/latticeai/runtime/router_registration.py +0 -693
- package/latticeai/runtime/service_singletons.py +0 -55
- package/latticeai/runtime/sso_config_runtime.py +0 -128
- package/latticeai/runtime/user_key_runtime.py +0 -106
- package/latticeai/runtime/web_runtime.py +0 -92
- package/latticeai/server_app.py +0 -51
- package/latticeai/services/app_context.py +0 -130
- package/latticeai/services/automation_execution.py +0 -266
- package/latticeai/services/automation_intelligence.py +0 -614
- package/latticeai/services/brain_automation.py +0 -191
- package/latticeai/services/brain_intelligence/__init__.py +0 -58
- package/latticeai/services/brain_intelligence/_contract.py +0 -71
- package/latticeai/services/brain_intelligence/consistency.py +0 -193
- package/latticeai/services/brain_intelligence/constants.py +0 -47
- package/latticeai/services/brain_intelligence/digest.py +0 -258
- package/latticeai/services/brain_intelligence/health.py +0 -331
- package/latticeai/services/brain_intelligence/proposals.py +0 -259
- package/latticeai/services/brain_intelligence/sampling.py +0 -84
- package/latticeai/services/brain_intelligence/service.py +0 -48
- package/latticeai/services/change_proposals.py +0 -471
- package/latticeai/services/chat_service.py +0 -243
- package/latticeai/services/chronicle.py +0 -555
- package/latticeai/services/cloud_egress_audit.py +0 -85
- package/latticeai/services/cloud_extraction.py +0 -129
- package/latticeai/services/cloud_streaming.py +0 -268
- package/latticeai/services/cloud_token_guard.py +0 -84
- package/latticeai/services/command_center.py +0 -548
- package/latticeai/services/evidence_actions.py +0 -258
- package/latticeai/services/feature_toggles.py +0 -502
- package/latticeai/services/folder_watch.py +0 -520
- package/latticeai/services/funnel_metrics.py +0 -307
- package/latticeai/services/hybrid_chat.py +0 -316
- package/latticeai/services/hybrid_context.py +0 -228
- package/latticeai/services/hybrid_policy.py +0 -129
- package/latticeai/services/interop_bridges.py +0 -978
- package/latticeai/services/local_knowledge.py +0 -465
- package/latticeai/services/memory_service/__init__.py +0 -52
- package/latticeai/services/memory_service/_contract.py +0 -100
- package/latticeai/services/memory_service/brief.py +0 -431
- package/latticeai/services/memory_service/constants.py +0 -57
- package/latticeai/services/memory_service/maintenance.py +0 -138
- package/latticeai/services/memory_service/manager.py +0 -186
- package/latticeai/services/memory_service/proof.py +0 -136
- package/latticeai/services/memory_service/recall.py +0 -225
- package/latticeai/services/memory_service/service.py +0 -48
- package/latticeai/services/memory_service/stores.py +0 -110
- package/latticeai/services/mode_store.py +0 -132
- package/latticeai/services/model_recommendation.py +0 -224
- package/latticeai/services/model_runtime/cloud.py +0 -87
- package/latticeai/services/network_boundary_service.py +0 -117
- package/latticeai/services/obsidian_bridge.py +0 -609
- package/latticeai/services/openai_compatible_adapter.py +0 -101
- package/latticeai/services/permission_mode_service.py +0 -122
- package/latticeai/services/platform_runtime.py +0 -366
- package/latticeai/services/review_queue.py +0 -380
- package/latticeai/services/router_context.py +0 -59
- package/latticeai/services/run_executor.py +0 -387
- package/latticeai/services/self_model_service.py +0 -171
- package/latticeai/services/setup_detection.py +0 -147
- package/latticeai/services/triggers.py +0 -378
- package/latticeai/services/upload_service.py +0 -172
- package/latticeai/services/workspace_service.py +0 -165
- package/latticeai/setup/__init__.py +0 -25
- package/latticeai/setup/auto_setup.py +0 -846
- package/latticeai/setup/demo_corpus.py +0 -98
- package/latticeai/setup/wizard/__init__.py +0 -126
- package/latticeai/setup/wizard/catalog.py +0 -175
- package/latticeai/setup/wizard/detect.py +0 -302
- package/latticeai/setup/wizard/install.py +0 -348
- package/latticeai/setup/wizard/paths.py +0 -165
- package/latticeai/setup/wizard/plans.py +0 -74
- package/latticeai/setup/wizard/recommend.py +0 -320
- package/scripts/bench_agent_smoke.py +0 -409
- package/scripts/bench_models.py +0 -540
- package/scripts/bench_vector_index.py +0 -295
- package/scripts/funnel_soft_gate.py +0 -192
- package/scripts/generate_agent_loop_fixtures.py +0 -994
- package/scripts/generate_rust_parity_fixtures.py +0 -908
- package/scripts/migrate_brain_storage.py +0 -57
- package/scripts/parity_fixture_corpus_context.py +0 -162
- package/scripts/parity_fixture_corpus_docgen.py +0 -341
- package/scripts/profile_kg.py +0 -355
- package/server.py +0 -30
- package/static/app/assets/AdminConsole-cf4npybT.js +0 -1
- package/static/app/assets/Capture-DiQ219jW.js +0 -1
- package/static/app/assets/System-CieofHQa.js +0 -1
- package/static/app/assets/arrow-left-kfsrk0mv.js +0 -1
- package/static/app/assets/circle-check-qqLug9nU.js +0 -1
- package/static/app/assets/index-DxmOfNRi.css +0 -2
- package/static/app/assets/primitives-SNp0LRJz.js +0 -1
- package/static/app/assets/search-BcHqkjoy.js +0 -1
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Dump the Python chat-turn redaction chain for the Rust parity test (WP-W3a).
|
|
3
|
+
|
|
4
|
+
``latticeai/runtime/history_writer.py`` step 1 is two pure functions:
|
|
5
|
+
|
|
6
|
+
* :func:`latticeai.core.security.redact_secret_text` — the secret-shape
|
|
7
|
+
redactor every turn passes through, and
|
|
8
|
+
* :func:`latticeai.models.router.branding.normalize_branding` — the
|
|
9
|
+
legacy-alias rewrite applied to **assistant** turns only.
|
|
10
|
+
|
|
11
|
+
Neither touches a model: ``redact_secret_text`` is eleven compiled regular
|
|
12
|
+
expressions and ``normalize_branding`` is four, so the whole of step 1 is
|
|
13
|
+
portable arithmetic over text. (The *ingest* step's concept extraction is
|
|
14
|
+
LLM-first and therefore is not — see the W3a wiring note.) This script is the
|
|
15
|
+
proof that the port agrees: it drives the real Python functions over a corpus
|
|
16
|
+
that reaches every rule branch and writes what they answered.
|
|
17
|
+
|
|
18
|
+
``rust/lattice-chat/tests/redact_parity.rs`` replays the corpus through
|
|
19
|
+
``lattice_chat::redact`` and asserts byte-identical output for all three
|
|
20
|
+
columns:
|
|
21
|
+
|
|
22
|
+
``redacted``
|
|
23
|
+
``redact_secret_text(input)`` — what a **user** turn stores.
|
|
24
|
+
``branded``
|
|
25
|
+
``normalize_branding(input)`` — the branding step on its own.
|
|
26
|
+
``assistant``
|
|
27
|
+
``normalize_branding(redact_secret_text(input))`` — the exact composition
|
|
28
|
+
``write_chat_turn`` applies when ``role == "assistant"``.
|
|
29
|
+
|
|
30
|
+
Determinism is the constraint: the corpus is a literal list in source order,
|
|
31
|
+
the functions are pure, and the file is written with sorted keys and a
|
|
32
|
+
trailing newline, so running the script twice produces the same bytes.
|
|
33
|
+
|
|
34
|
+
Usage::
|
|
35
|
+
|
|
36
|
+
.venv/bin/python scripts/gen_redact_fixture.py
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
from __future__ import annotations
|
|
40
|
+
|
|
41
|
+
import json
|
|
42
|
+
import sys
|
|
43
|
+
from pathlib import Path
|
|
44
|
+
from typing import Dict, List
|
|
45
|
+
|
|
46
|
+
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
47
|
+
if str(REPO_ROOT) not in sys.path:
|
|
48
|
+
sys.path.insert(0, str(REPO_ROOT))
|
|
49
|
+
|
|
50
|
+
from latticeai.core.security import ( # noqa: E402
|
|
51
|
+
SECRET_TEXT_PATTERNS,
|
|
52
|
+
TELEGRAM_TOKEN_BARE_RE,
|
|
53
|
+
TELEGRAM_TOKEN_WITH_BOT_RE,
|
|
54
|
+
redact_secret_text,
|
|
55
|
+
)
|
|
56
|
+
from latticeai.models.router.branding import ( # noqa: E402
|
|
57
|
+
BRAND_NAME,
|
|
58
|
+
LEGACY_BRAND_PATTERNS,
|
|
59
|
+
normalize_branding,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
OUTPUT = REPO_ROOT / "rust" / "fixtures" / "redact.json"
|
|
63
|
+
|
|
64
|
+
#: One entry per branch of the two rule sets, plus the negatives that prove a
|
|
65
|
+
#: branch does *not* fire. ``case`` is the branch it exists for; the Rust test
|
|
66
|
+
#: reports it when an assertion fails, so a divergence names its own rule.
|
|
67
|
+
CORPUS: List[Dict[str, str]] = [
|
|
68
|
+
# ── nothing to do ───────────────────────────────────────────────────────
|
|
69
|
+
{"case": "empty", "text": ""},
|
|
70
|
+
{"case": "plain", "text": "nothing secret here"},
|
|
71
|
+
{"case": "korean_plain", "text": "안녕하세요. 오늘 회의록을 정리해 주세요."},
|
|
72
|
+
# ── keyed pattern (group 1 kept, group 2 dropped) ───────────────────────
|
|
73
|
+
{"case": "keyed_api_key_colon", "text": "api_key: abcdefgh12345678"},
|
|
74
|
+
{"case": "keyed_api_key_space", "text": "api key = abcdefgh12345678"},
|
|
75
|
+
{"case": "keyed_api_key_dash", "text": "api-key:abcdefgh12345678"},
|
|
76
|
+
{"case": "keyed_api_key_upper", "text": "API_KEY: ABCDEFGH12345678"},
|
|
77
|
+
{"case": "keyed_secret", "text": "secret = 'sup3rsecretvalue'"},
|
|
78
|
+
{"case": "keyed_token_quoted", "text": 'token: "abcdefgh12345678"'},
|
|
79
|
+
{"case": "keyed_password", "text": "password=hunter2hunter2"},
|
|
80
|
+
{"case": "keyed_passwd", "text": "passwd : abcdefgh1234"},
|
|
81
|
+
{"case": "keyed_authorization", "text": "Authorization: Bearer abcdefgh12345678"},
|
|
82
|
+
{"case": "keyed_bearer", "text": "bearer=abcdefgh12345678"},
|
|
83
|
+
{"case": "keyed_client_secret", "text": "client_secret: abcdefgh12345678"},
|
|
84
|
+
{"case": "keyed_client_secret_dash", "text": "client-secret = abcdefgh12345678"},
|
|
85
|
+
{"case": "keyed_webhook", "text": "webhook: https://hooks.example.com/T0/B0/xyz"},
|
|
86
|
+
{"case": "keyed_dsn", "text": "dsn=postgres-dsn-value-1234"},
|
|
87
|
+
{"case": "keyed_too_short", "text": "token: short"},
|
|
88
|
+
{"case": "keyed_korean_sentence", "text": "제 api_key: abcdefgh12345678 입니다"},
|
|
89
|
+
{"case": "keyed_two_on_one_line", "text": "token: abcdefgh12345678 secret: zyxwvu9876543210"},
|
|
90
|
+
# ── shaped patterns (whole match dropped) ───────────────────────────────
|
|
91
|
+
{"case": "shape_openai", "text": "value sk-abcdefghijklmnop01 end"},
|
|
92
|
+
{"case": "shape_xai", "text": "value xai-abcdefghijklmnop01 end"},
|
|
93
|
+
{"case": "shape_groq", "text": "value gsk_abcdefghijklmnop01 end"},
|
|
94
|
+
{"case": "shape_github", "text": "value ghp_" + "a" * 30 + " end"},
|
|
95
|
+
{"case": "shape_github_short", "text": "value ghp_" + "a" * 20 + " end"},
|
|
96
|
+
{"case": "shape_slack_bot", "text": "value xoxb-1234567890-abc end"},
|
|
97
|
+
{"case": "shape_slack_user", "text": "value xoxp-1234567890-abc end"},
|
|
98
|
+
{"case": "shape_slack_refresh", "text": "value xoxr-1234567890-abc end"},
|
|
99
|
+
{"case": "shape_slack_app", "text": "value xoxa-1234567890-abc end"},
|
|
100
|
+
{"case": "shape_slack_service", "text": "value xoxs-1234567890-abc end"},
|
|
101
|
+
{"case": "shape_aws", "text": "value AKIAABCDEFGHIJKLMNOP end"},
|
|
102
|
+
{"case": "shape_aws_lowercase_tail", "text": "value AKIAabcdefghijklmnop end"},
|
|
103
|
+
{"case": "shape_postgres", "text": "postgres://u:p@host/db"},
|
|
104
|
+
{"case": "shape_postgresql", "text": "POSTGRESQL://user:pw@10.0.0.1:5432/app"},
|
|
105
|
+
{
|
|
106
|
+
"case": "shape_private_key",
|
|
107
|
+
"text": "-----BEGIN RSA PRIVATE KEY-----\nMIIE\nabc\n-----END RSA PRIVATE KEY-----",
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"case": "shape_private_key_openssh",
|
|
111
|
+
"text": "head\n-----BEGIN OPENSSH PRIVATE KEY-----\nx\n-----END OPENSSH PRIVATE KEY-----\ntail",
|
|
112
|
+
},
|
|
113
|
+
# ── telegram tokens (rewritten, not blanked) ────────────────────────────
|
|
114
|
+
{"case": "telegram_with_bot", "text": "bot123456:abcdefghij"},
|
|
115
|
+
{"case": "telegram_bare", "text": "123456:abcdefghij"},
|
|
116
|
+
{"case": "telegram_bare_in_sentence", "text": "토큰은 1234567:AAEEabcdefghij 입니다"},
|
|
117
|
+
{"case": "telegram_lookbehind_blocked", "text": "x123456:abcdefghij"},
|
|
118
|
+
# The trailing lookahead never fires: `[A-Za-z0-9_-]{8,}` is greedy, so it
|
|
119
|
+
# swallows the tail and the lookahead is satisfied at end of string.
|
|
120
|
+
{"case": "telegram_lookahead_is_greedy", "text": "123456:abcdefghij-more_TAIL"},
|
|
121
|
+
{"case": "telegram_too_short_digits", "text": "12:34"},
|
|
122
|
+
{"case": "telegram_url_colon", "text": "https://host:123456:abcdefghij"},
|
|
123
|
+
# ── things that must survive (the classifier's job, not the redactor's) ─
|
|
124
|
+
{"case": "email_plain", "text": "연락처는 owner@example.com 입니다"},
|
|
125
|
+
{"case": "email_plus", "text": "a.b+tag_1%x@sub.example.co.kr"},
|
|
126
|
+
{"case": "email_and_key", "text": "owner@example.com api_key: abcdefgh12345678"},
|
|
127
|
+
{"case": "phone_korean", "text": "010-1234-5678 로 연락 주세요"},
|
|
128
|
+
{"case": "rrn_korean", "text": "주민등록번호 900101-1234567"},
|
|
129
|
+
{"case": "card_number", "text": "카드번호 4111 1111 1111 1111"},
|
|
130
|
+
# ── branding rewrite (assistant turns) ──────────────────────────────────
|
|
131
|
+
{"case": "brand_space", "text": "I am Connect AI, your assistant."},
|
|
132
|
+
{"case": "brand_space_lower", "text": "connect ai here"},
|
|
133
|
+
{"case": "brand_space_multi", "text": "connect ai here"},
|
|
134
|
+
{"case": "brand_hyphen", "text": "connect-ai release notes"},
|
|
135
|
+
{"case": "brand_joined", "text": "ConnectAI is the old name"},
|
|
136
|
+
{"case": "brand_korean", "text": "저는 커넥트 AI 입니다"},
|
|
137
|
+
{"case": "brand_korean_tight", "text": "저는 커넥트AI 입니다"},
|
|
138
|
+
{"case": "brand_korean_wide", "text": "저는 커넥트 ai 입니다"},
|
|
139
|
+
{"case": "brand_not_a_word", "text": "disconnectai should not change"},
|
|
140
|
+
{"case": "brand_already_right", "text": "Lattice AI is the product name"},
|
|
141
|
+
{"case": "brand_and_secret", "text": "Connect AI says api_key: abcdefgh12345678"},
|
|
142
|
+
{"case": "brand_and_telegram", "text": "connect-ai token 123456:abcdefghij"},
|
|
143
|
+
# ── shape/ordering interactions ─────────────────────────────────────────
|
|
144
|
+
{"case": "multiline_mixed", "text": "line1 sk-abcdefghijklmnop01\nline2 커넥트 AI\nline3 ok"},
|
|
145
|
+
{"case": "keyed_wins_over_shape", "text": "token: sk-abcdefghijklmnop01"},
|
|
146
|
+
{"case": "trailing_punctuation", "text": "(api_key: abcdefgh12345678), done."},
|
|
147
|
+
{"case": "unicode_emoji", "text": "🔐 secret: abcdefgh12345678 🔐"},
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def build() -> Dict[str, object]:
|
|
152
|
+
"""The fixture body: the rule inventory, then the corpus with answers."""
|
|
153
|
+
rows = []
|
|
154
|
+
for entry in CORPUS:
|
|
155
|
+
text = entry["text"]
|
|
156
|
+
redacted = redact_secret_text(text)
|
|
157
|
+
rows.append(
|
|
158
|
+
{
|
|
159
|
+
"case": entry["case"],
|
|
160
|
+
"text": text,
|
|
161
|
+
# `write_chat_turn` step 1, both roles.
|
|
162
|
+
"redacted": redacted,
|
|
163
|
+
"branded": normalize_branding(text),
|
|
164
|
+
"assistant": normalize_branding(redacted),
|
|
165
|
+
}
|
|
166
|
+
)
|
|
167
|
+
return {
|
|
168
|
+
"source": "latticeai.core.security.redact_secret_text + "
|
|
169
|
+
"latticeai.models.router.branding.normalize_branding",
|
|
170
|
+
"brand_name": BRAND_NAME,
|
|
171
|
+
# The Rust port hard-codes the same pattern list; recording it here
|
|
172
|
+
# makes a Python-side edit show up as a fixture diff rather than as a
|
|
173
|
+
# silent divergence nobody notices until a token leaks.
|
|
174
|
+
"secret_patterns": [pattern.pattern for pattern in SECRET_TEXT_PATTERNS],
|
|
175
|
+
"telegram_patterns": [
|
|
176
|
+
TELEGRAM_TOKEN_WITH_BOT_RE.pattern,
|
|
177
|
+
TELEGRAM_TOKEN_BARE_RE.pattern,
|
|
178
|
+
],
|
|
179
|
+
"brand_patterns": [pattern.pattern for pattern, _ in LEGACY_BRAND_PATTERNS],
|
|
180
|
+
"cases": rows,
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def main() -> int:
|
|
185
|
+
payload = build()
|
|
186
|
+
OUTPUT.parent.mkdir(parents=True, exist_ok=True)
|
|
187
|
+
OUTPUT.write_text(
|
|
188
|
+
json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True) + "\n",
|
|
189
|
+
encoding="utf-8",
|
|
190
|
+
)
|
|
191
|
+
print(f"wrote {OUTPUT.relative_to(REPO_ROOT)} — {len(payload['cases'])} cases")
|
|
192
|
+
return 0
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
if __name__ == "__main__":
|
|
196
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Project the worker profile's route set into the fixture Rust proxies from.
|
|
2
|
+
|
|
3
|
+
The v11.6.0 gateway inverts the reverse proxy: instead of forwarding everything
|
|
4
|
+
it does not serve itself, it forwards **only** what the Python worker actually
|
|
5
|
+
mounts, and answers 404 for the rest. That allowlist has exactly one source of
|
|
6
|
+
truth — :func:`latticeai.runtime.build_phases.worker_profile.worker_route_keys`
|
|
7
|
+
— and this script writes it down where a Rust crate can read it at compile
|
|
8
|
+
time.
|
|
9
|
+
|
|
10
|
+
Two spellings per route, because the two runtimes disagree about path syntax
|
|
11
|
+
and only one of them can be the file's:
|
|
12
|
+
|
|
13
|
+
* ``path`` is FastAPI's, converters included (``/models/switch/{model_id:path}``).
|
|
14
|
+
It is what ``APIRoute.path`` returns, so the Python side compares without
|
|
15
|
+
normalisation.
|
|
16
|
+
* ``axum`` is the same route as axum 0.7 spells it (``/models/switch/*model_id``).
|
|
17
|
+
A ``{name:path}`` converter matches slashes; a plain ``:name`` capture does
|
|
18
|
+
not, so an id containing a ``/`` would 404 at the front door while working
|
|
19
|
+
against the worker directly. WP-I5's ``greedy_path_params`` records the same
|
|
20
|
+
fact for the public contract.
|
|
21
|
+
|
|
22
|
+
Usage::
|
|
23
|
+
|
|
24
|
+
.venv/bin/python scripts/gen_worker_allowlist_fixture.py
|
|
25
|
+
|
|
26
|
+
Running it twice must produce the same bytes; ``tests/unit/test_worker_allowlist.py``
|
|
27
|
+
asserts the committed file still equals ``worker_route_keys()``.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
import json
|
|
33
|
+
import re
|
|
34
|
+
import sys
|
|
35
|
+
from pathlib import Path
|
|
36
|
+
from typing import Any, Dict, List
|
|
37
|
+
|
|
38
|
+
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
39
|
+
if str(REPO_ROOT) not in sys.path:
|
|
40
|
+
sys.path.insert(0, str(REPO_ROOT))
|
|
41
|
+
|
|
42
|
+
from latticeai.runtime.build_phases.worker_profile import ( # noqa: E402
|
|
43
|
+
WORKER_COMPUTE_ROUTES,
|
|
44
|
+
WORKER_ROUTES,
|
|
45
|
+
WORKER_SEAM_ROUTES,
|
|
46
|
+
worker_route_keys,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
FIXTURE_PATH = REPO_ROOT / "rust" / "fixtures" / "worker_allowlist.json"
|
|
50
|
+
SCHEMA = "worker-proxy-allowlist/v1"
|
|
51
|
+
|
|
52
|
+
#: ``{name:path}`` — FastAPI's greedy converter. Anything else is one segment.
|
|
53
|
+
_GREEDY = re.compile(r"\{([A-Za-z_][A-Za-z0-9_]*):path\}")
|
|
54
|
+
#: ``{name}`` — an ordinary single-segment parameter.
|
|
55
|
+
_PLAIN = re.compile(r"\{([A-Za-z_][A-Za-z0-9_]*)\}")
|
|
56
|
+
|
|
57
|
+
#: Which tuple a route came from, so a reader can see *why* it is allowed.
|
|
58
|
+
GROUPS = (
|
|
59
|
+
("product", WORKER_ROUTES),
|
|
60
|
+
("state_seam", WORKER_SEAM_ROUTES),
|
|
61
|
+
("compute_seam", WORKER_COMPUTE_ROUTES),
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def axum_path(path: str) -> str:
|
|
66
|
+
"""FastAPI's path as axum 0.7 spells it."""
|
|
67
|
+
path = _GREEDY.sub(r"*\1", path)
|
|
68
|
+
return _PLAIN.sub(r":\1", path)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def build() -> Dict[str, Any]:
|
|
72
|
+
"""The fixture document."""
|
|
73
|
+
group_of = {
|
|
74
|
+
(method, path): name for name, routes in GROUPS for method, path in routes
|
|
75
|
+
}
|
|
76
|
+
routes: List[Dict[str, str]] = []
|
|
77
|
+
for method, path in sorted(worker_route_keys()):
|
|
78
|
+
routes.append(
|
|
79
|
+
{
|
|
80
|
+
"method": method,
|
|
81
|
+
"path": path,
|
|
82
|
+
"axum": axum_path(path),
|
|
83
|
+
"group": group_of[(method, path)],
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
return {
|
|
87
|
+
"schema": SCHEMA,
|
|
88
|
+
"note": (
|
|
89
|
+
"The gateway's reverse proxy allowlist. Generated from "
|
|
90
|
+
"latticeai.runtime.build_phases.worker_profile.worker_route_keys() "
|
|
91
|
+
"by scripts/gen_worker_allowlist_fixture.py; a path absent here is "
|
|
92
|
+
"answered natively or 404, never forwarded."
|
|
93
|
+
),
|
|
94
|
+
"source": "latticeai/runtime/build_phases/worker_profile.py",
|
|
95
|
+
"generated_by": "scripts/gen_worker_allowlist_fixture.py",
|
|
96
|
+
"count": len(routes),
|
|
97
|
+
"routes": routes,
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def main() -> int:
|
|
102
|
+
document = build()
|
|
103
|
+
FIXTURE_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
104
|
+
FIXTURE_PATH.write_text(
|
|
105
|
+
json.dumps(document, indent=2, sort_keys=True, ensure_ascii=True) + "\n",
|
|
106
|
+
encoding="utf-8",
|
|
107
|
+
)
|
|
108
|
+
print(
|
|
109
|
+
f"wrote {FIXTURE_PATH.relative_to(REPO_ROOT)} ({document['count']} routes)",
|
|
110
|
+
)
|
|
111
|
+
return 0
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
if __name__ == "__main__": # pragma: no cover - script entry point
|
|
115
|
+
raise SystemExit(main())
|
|
@@ -47,7 +47,6 @@ from __future__ import annotations
|
|
|
47
47
|
import json
|
|
48
48
|
import os
|
|
49
49
|
import shlex
|
|
50
|
-
import shutil
|
|
51
50
|
import subprocess
|
|
52
51
|
import sys
|
|
53
52
|
import tempfile
|
|
@@ -386,7 +385,8 @@ def validation_only() -> Iterator[List[str]]:
|
|
|
386
385
|
the caller can assert the fixed PATH was the one searched.
|
|
387
386
|
"""
|
|
388
387
|
searched: List[str] = []
|
|
389
|
-
real_subprocess
|
|
388
|
+
real_subprocess = command_tools.subprocess
|
|
389
|
+
real_shutil = getattr(command_tools, "shutil", None)
|
|
390
390
|
|
|
391
391
|
class _SubprocessShim:
|
|
392
392
|
TimeoutExpired = subprocess.TimeoutExpired
|
|
@@ -407,7 +407,10 @@ def validation_only() -> Iterator[List[str]]:
|
|
|
407
407
|
yield searched
|
|
408
408
|
finally:
|
|
409
409
|
command_tools.subprocess = real_subprocess
|
|
410
|
-
|
|
410
|
+
if real_shutil is None:
|
|
411
|
+
delattr(command_tools, "shutil")
|
|
412
|
+
else:
|
|
413
|
+
command_tools.shutil = real_shutil
|
|
411
414
|
|
|
412
415
|
|
|
413
416
|
def _error(exc: BaseException) -> Dict[str, str]:
|
|
@@ -690,8 +693,16 @@ def _dump_grid(path: Path, header: Dict[str, Any], groups: Dict[str, List[Any]])
|
|
|
690
693
|
|
|
691
694
|
|
|
692
695
|
def build(root: Path) -> Dict[str, Callable[[], None]]:
|
|
693
|
-
"""Every golden, keyed by filename, as a thunk that writes it.
|
|
694
|
-
|
|
696
|
+
"""Every golden, keyed by filename, as a thunk that writes it.
|
|
697
|
+
|
|
698
|
+
"""
|
|
699
|
+
# run_command left the worker (WP-P1). commands.json / execution.json
|
|
700
|
+
# stay FROZEN at fc65e60; only rewrite them when the last generating
|
|
701
|
+
# commands module is still importable (recovery / historical tree).
|
|
702
|
+
if hasattr(command_tools, "run_command"):
|
|
703
|
+
commands, spawn_env, searched = command_rows(root)
|
|
704
|
+
else:
|
|
705
|
+
commands, spawn_env, searched = None, None, [command_tools._SAFE_EXECUTABLE_PATH]
|
|
695
706
|
return {
|
|
696
707
|
"manifest.json": lambda: _dump(GOLDEN_DIR / "manifest.json", manifest(searched)),
|
|
697
708
|
"policies.json": lambda: _dump(GOLDEN_DIR / "policies.json", policy_table()),
|
|
@@ -705,14 +716,22 @@ def build(root: Path) -> Dict[str, Callable[[], None]]:
|
|
|
705
716
|
"shlex.json": lambda: _dump_grid(
|
|
706
717
|
GOLDEN_DIR / "shlex.json", {"schema": SCHEMA}, {"cases": shlex_rows()},
|
|
707
718
|
),
|
|
708
|
-
"commands.json":
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
719
|
+
"commands.json": (
|
|
720
|
+
(lambda: _dump_grid(
|
|
721
|
+
GOLDEN_DIR / "commands.json",
|
|
722
|
+
{"schema": SCHEMA, "spawn_env": spawn_env},
|
|
723
|
+
{"cases": commands},
|
|
724
|
+
))
|
|
725
|
+
if commands is not None
|
|
726
|
+
else (lambda: None)
|
|
712
727
|
),
|
|
713
|
-
"execution.json":
|
|
714
|
-
|
|
715
|
-
|
|
728
|
+
"execution.json": (
|
|
729
|
+
(lambda: _dump_grid(
|
|
730
|
+
GOLDEN_DIR / "execution.json", {"schema": SCHEMA},
|
|
731
|
+
{"cases": execution_rows(root)},
|
|
732
|
+
))
|
|
733
|
+
if commands is not None
|
|
734
|
+
else (lambda: None)
|
|
716
735
|
),
|
|
717
736
|
"paths.json": lambda: _dump_grid(
|
|
718
737
|
GOLDEN_DIR / "paths.json", {"schema": SCHEMA}, {"cases": path_rows(root)},
|
|
@@ -733,8 +752,8 @@ def build(root: Path) -> Dict[str, Callable[[], None]]:
|
|
|
733
752
|
|
|
734
753
|
|
|
735
754
|
def main() -> int:
|
|
736
|
-
|
|
737
|
-
|
|
755
|
+
# Never rmtree: commands.json / execution.json are FROZEN at fc65e60
|
|
756
|
+
# once run_command leaves the worker. Write other goldens in place.
|
|
738
757
|
GOLDEN_DIR.mkdir(parents=True, exist_ok=True)
|
|
739
758
|
with pinned_environment(), tempfile.TemporaryDirectory() as tmp:
|
|
740
759
|
root = Path(tmp) / "agent_workspace"
|