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
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
"""Workspace OS vocabulary: types, roles, permissions, areas, defaults.
|
|
2
|
-
|
|
3
|
-
Split out of ``workspace_os.py`` in 10.2.0 so the store module holds behaviour
|
|
4
|
-
and this one holds the vocabulary that behaviour is written against. Every name
|
|
5
|
-
is re-exported from ``workspace_os`` — the import path callers use has not
|
|
6
|
-
changed.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
from typing import Dict
|
|
12
|
-
|
|
13
|
-
WORKSPACE_OS_VERSION = "11.5.2"
|
|
14
|
-
|
|
15
|
-
# Workspace types separate single-user Personal workspaces from shared
|
|
16
|
-
# Organization workspaces. Both keep the same local-first JSON store; the type
|
|
17
|
-
# only changes how membership and permissions are evaluated.
|
|
18
|
-
WORKSPACE_TYPES = ("personal", "organization")
|
|
19
|
-
|
|
20
|
-
DEFAULT_WORKSPACE_ID = "personal"
|
|
21
|
-
|
|
22
|
-
# Role hierarchy for Organization workspaces. Personal workspaces always grant
|
|
23
|
-
# their single local user the owner role.
|
|
24
|
-
WORKSPACE_ROLES = ("owner", "admin", "member", "viewer")
|
|
25
|
-
|
|
26
|
-
# Capability-style permissions. Kept intentionally small so Enterprise editions
|
|
27
|
-
# can layer advanced RBAC/ABAC on top via the enterprise seam without changing
|
|
28
|
-
# these community defaults.
|
|
29
|
-
WORKSPACE_PERMISSIONS = ("read", "write", "manage_members", "manage_workspace")
|
|
30
|
-
|
|
31
|
-
ROLE_PERMISSIONS: Dict[str, set] = {
|
|
32
|
-
"owner": {"read", "write", "manage_members", "manage_workspace"},
|
|
33
|
-
"admin": {"read", "write", "manage_members", "manage_workspace"},
|
|
34
|
-
"member": {"read", "write"},
|
|
35
|
-
"viewer": {"read"},
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
WORKSPACE_AREAS = [
|
|
39
|
-
"graph",
|
|
40
|
-
"snapshot",
|
|
41
|
-
"memory",
|
|
42
|
-
"agent",
|
|
43
|
-
"workflow",
|
|
44
|
-
"plugins",
|
|
45
|
-
"skills",
|
|
46
|
-
"marketplace",
|
|
47
|
-
"timeline",
|
|
48
|
-
]
|
|
49
|
-
|
|
50
|
-
ONBOARDING_STEPS = [
|
|
51
|
-
"account",
|
|
52
|
-
"admin",
|
|
53
|
-
"hardware",
|
|
54
|
-
"model_recommendation",
|
|
55
|
-
"model_install",
|
|
56
|
-
"model_connection",
|
|
57
|
-
"folder_connection",
|
|
58
|
-
"first_question",
|
|
59
|
-
"complete",
|
|
60
|
-
]
|
|
61
|
-
|
|
62
|
-
MEMORY_KINDS = {
|
|
63
|
-
"short_term",
|
|
64
|
-
"workspace",
|
|
65
|
-
"preferences",
|
|
66
|
-
"decisions",
|
|
67
|
-
"working_style",
|
|
68
|
-
"frequently_used_tools",
|
|
69
|
-
"long_term",
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
EXECUTION_EVENT_TYPES = {
|
|
73
|
-
"agent_started",
|
|
74
|
-
"handoff_created",
|
|
75
|
-
"handoff_accepted",
|
|
76
|
-
"handoff_completed",
|
|
77
|
-
"review_requested",
|
|
78
|
-
"review_approved",
|
|
79
|
-
"review_rejected",
|
|
80
|
-
"retry_requested",
|
|
81
|
-
"workflow_started",
|
|
82
|
-
"workflow_completed",
|
|
83
|
-
"plugin_started",
|
|
84
|
-
"plugin_completed",
|
|
85
|
-
"execution_failed",
|
|
86
|
-
"execution_cancelled",
|
|
87
|
-
"execution_interrupted",
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
DEFAULT_AGENTS = [
|
|
91
|
-
{
|
|
92
|
-
"id": "agent:planner",
|
|
93
|
-
"name": "Planner",
|
|
94
|
-
"role": "Breaks workspace goals into executable plans.",
|
|
95
|
-
"status": "available",
|
|
96
|
-
"relationships": ["agent:executor", "agent:reviewer"],
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
"id": "agent:executor",
|
|
100
|
-
"name": "Executor",
|
|
101
|
-
"role": "Runs approved tool and code workflows.",
|
|
102
|
-
"status": "available",
|
|
103
|
-
"relationships": ["agent:planner", "agent:reviewer"],
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
"id": "agent:reviewer",
|
|
107
|
-
"name": "Reviewer",
|
|
108
|
-
"role": "Checks outputs, tests, and regressions.",
|
|
109
|
-
"status": "available",
|
|
110
|
-
"relationships": ["agent:executor", "agent:release"],
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
"id": "agent:researcher",
|
|
114
|
-
"name": "Researcher",
|
|
115
|
-
"role": "Finds and curates relevant workspace knowledge.",
|
|
116
|
-
"status": "available",
|
|
117
|
-
"relationships": ["agent:planner"],
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
"id": "agent:release",
|
|
121
|
-
"name": "Release Agent",
|
|
122
|
-
"role": "Coordinates versioning, packaging, and release checks.",
|
|
123
|
-
"status": "available",
|
|
124
|
-
"relationships": ["agent:reviewer"],
|
|
125
|
-
},
|
|
126
|
-
]
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
"""Workspace OS state: the shape of a new file, and upgrades to old ones.
|
|
2
|
-
|
|
3
|
-
Split out of ``workspace_os.py`` in 10.2.0. Neither concern belongs to the
|
|
4
|
-
store: ``default_state`` describes a brand-new workspace file, ``new_workspace_record``
|
|
5
|
-
builds one workspace entry, and ``migrate_workspaces`` upgrades a file written
|
|
6
|
-
by an older version. All three were already free of instance state — two were
|
|
7
|
-
``@staticmethod`` in all but name — so they move without behaviour change.
|
|
8
|
-
|
|
9
|
-
``WorkspaceOSStore`` keeps thin delegating methods, so its public surface and
|
|
10
|
-
every existing call site are unchanged.
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
from __future__ import annotations
|
|
14
|
-
|
|
15
|
-
from typing import Any, Dict, List, Optional
|
|
16
|
-
|
|
17
|
-
from .timeutil import now_iso as _now
|
|
18
|
-
from .workspace_os_constants import (
|
|
19
|
-
DEFAULT_AGENTS,
|
|
20
|
-
DEFAULT_WORKSPACE_ID,
|
|
21
|
-
ONBOARDING_STEPS,
|
|
22
|
-
ROLE_PERMISSIONS,
|
|
23
|
-
WORKSPACE_AREAS,
|
|
24
|
-
WORKSPACE_OS_VERSION,
|
|
25
|
-
WORKSPACE_TYPES,
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def new_workspace_record(
|
|
30
|
-
*,
|
|
31
|
-
workspace_id: str,
|
|
32
|
-
name: str,
|
|
33
|
-
workspace_type: str,
|
|
34
|
-
owner_user_id: Optional[str],
|
|
35
|
-
settings: Optional[Dict[str, Any]] = None,
|
|
36
|
-
members: Optional[List[Dict[str, Any]]] = None,
|
|
37
|
-
) -> Dict[str, Any]:
|
|
38
|
-
if workspace_type not in WORKSPACE_TYPES:
|
|
39
|
-
raise ValueError(f"unknown workspace type: {workspace_type}")
|
|
40
|
-
now = _now()
|
|
41
|
-
member_list = list(members or [])
|
|
42
|
-
if owner_user_id and not any(m.get("user_id") == owner_user_id for m in member_list):
|
|
43
|
-
member_list.insert(0, {"user_id": owner_user_id, "role": "owner", "added_at": now})
|
|
44
|
-
return {
|
|
45
|
-
"workspace_id": workspace_id,
|
|
46
|
-
"id": workspace_id,
|
|
47
|
-
"name": name,
|
|
48
|
-
"type": workspace_type,
|
|
49
|
-
"owner_user_id": owner_user_id,
|
|
50
|
-
"members": member_list,
|
|
51
|
-
"roles": {role: sorted(perms) for role, perms in ROLE_PERMISSIONS.items()},
|
|
52
|
-
"status": "active",
|
|
53
|
-
"areas": list(WORKSPACE_AREAS),
|
|
54
|
-
"settings": settings or {},
|
|
55
|
-
"created_at": now,
|
|
56
|
-
"updated_at": now,
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def migrate_workspaces(state: Dict[str, Any]) -> Dict[str, Any]:
|
|
61
|
-
"""Non-destructive upgrade of legacy workspace entries to the v1.1 model.
|
|
62
|
-
|
|
63
|
-
Existing 1.0.x state files stored minimal ``{id,name,type,areas}`` dicts.
|
|
64
|
-
This backfills membership/role/timestamp fields without dropping data and
|
|
65
|
-
guarantees the default Personal workspace always exists.
|
|
66
|
-
"""
|
|
67
|
-
workspaces = state.get("workspaces")
|
|
68
|
-
if not isinstance(workspaces, dict):
|
|
69
|
-
workspaces = {}
|
|
70
|
-
migrated: Dict[str, Any] = {}
|
|
71
|
-
for ws_id, ws in workspaces.items():
|
|
72
|
-
if not isinstance(ws, dict):
|
|
73
|
-
continue
|
|
74
|
-
ws_type = str(ws.get("type")) if ws.get("type") in WORKSPACE_TYPES else "organization"
|
|
75
|
-
if ws_id == DEFAULT_WORKSPACE_ID:
|
|
76
|
-
ws_type = "personal"
|
|
77
|
-
base = new_workspace_record(
|
|
78
|
-
workspace_id=ws_id,
|
|
79
|
-
name=ws.get("name") or ws_id,
|
|
80
|
-
workspace_type=ws_type,
|
|
81
|
-
owner_user_id=ws.get("owner_user_id"),
|
|
82
|
-
settings=ws.get("settings") or {},
|
|
83
|
-
members=ws.get("members") if isinstance(ws.get("members"), list) else None,
|
|
84
|
-
)
|
|
85
|
-
# Preserve any pre-existing timestamps / status from the loaded record.
|
|
86
|
-
base["created_at"] = ws.get("created_at") or base["created_at"]
|
|
87
|
-
base["updated_at"] = ws.get("updated_at") or base["updated_at"]
|
|
88
|
-
base["status"] = ws.get("status") or base["status"]
|
|
89
|
-
migrated[ws_id] = base
|
|
90
|
-
if DEFAULT_WORKSPACE_ID not in migrated:
|
|
91
|
-
migrated[DEFAULT_WORKSPACE_ID] = new_workspace_record(
|
|
92
|
-
workspace_id=DEFAULT_WORKSPACE_ID,
|
|
93
|
-
name="Personal Workspace",
|
|
94
|
-
workspace_type="personal",
|
|
95
|
-
owner_user_id=None,
|
|
96
|
-
)
|
|
97
|
-
state["workspaces"] = migrated
|
|
98
|
-
active = state.get("active_workspace")
|
|
99
|
-
if active not in migrated:
|
|
100
|
-
state["active_workspace"] = DEFAULT_WORKSPACE_ID
|
|
101
|
-
return state
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def default_state() -> Dict[str, Any]:
|
|
105
|
-
return {
|
|
106
|
-
"version": WORKSPACE_OS_VERSION,
|
|
107
|
-
"identity": "AI Workspace OS",
|
|
108
|
-
"created_at": _now(),
|
|
109
|
-
"updated_at": _now(),
|
|
110
|
-
"active_workspace": DEFAULT_WORKSPACE_ID,
|
|
111
|
-
"workspaces": {
|
|
112
|
-
DEFAULT_WORKSPACE_ID: new_workspace_record(
|
|
113
|
-
workspace_id=DEFAULT_WORKSPACE_ID,
|
|
114
|
-
name="Personal Workspace",
|
|
115
|
-
workspace_type="personal",
|
|
116
|
-
owner_user_id=None,
|
|
117
|
-
),
|
|
118
|
-
},
|
|
119
|
-
"feature_flags": {
|
|
120
|
-
"workspace_os": True,
|
|
121
|
-
"graph_trace": True,
|
|
122
|
-
"snapshots": True,
|
|
123
|
-
"personal_memory": True,
|
|
124
|
-
"multi_agent_graph": True,
|
|
125
|
-
"workflow_graph": True,
|
|
126
|
-
"skill_marketplace": True,
|
|
127
|
-
"local_computer_memory": False,
|
|
128
|
-
"organization_workspaces": True,
|
|
129
|
-
"enterprise_seam": True,
|
|
130
|
-
"plugin_sdk": True,
|
|
131
|
-
"workflow_designer": True,
|
|
132
|
-
"multi_agent_runtime": True,
|
|
133
|
-
"realtime_collaboration": True,
|
|
134
|
-
"agent_handoff": True,
|
|
135
|
-
"agent_context_packets": True,
|
|
136
|
-
"review_retry_loops": True,
|
|
137
|
-
"timeline_replay": True,
|
|
138
|
-
"agent_memory": True,
|
|
139
|
-
"agent_planning": True,
|
|
140
|
-
"marketplace_foundation": True,
|
|
141
|
-
"realtime_execution_observability": True,
|
|
142
|
-
},
|
|
143
|
-
"onboarding": {
|
|
144
|
-
"completed": False,
|
|
145
|
-
"current_step": "account",
|
|
146
|
-
"steps": {
|
|
147
|
-
step: {
|
|
148
|
-
"id": step,
|
|
149
|
-
"status": "pending",
|
|
150
|
-
"data": {},
|
|
151
|
-
"error": "",
|
|
152
|
-
"updated_at": None,
|
|
153
|
-
}
|
|
154
|
-
for step in ONBOARDING_STEPS
|
|
155
|
-
},
|
|
156
|
-
},
|
|
157
|
-
"snapshots": [],
|
|
158
|
-
"traces": [],
|
|
159
|
-
"memories": [],
|
|
160
|
-
"memory_snapshots": [],
|
|
161
|
-
"agents": list(DEFAULT_AGENTS),
|
|
162
|
-
"agent_runs": [],
|
|
163
|
-
"handoffs": [],
|
|
164
|
-
"workflows": [],
|
|
165
|
-
"workflow_runs": [],
|
|
166
|
-
"review_items": [],
|
|
167
|
-
"skill_registry": {},
|
|
168
|
-
"plugin_registry": {},
|
|
169
|
-
"template_registry": {},
|
|
170
|
-
"computer_memory": {
|
|
171
|
-
"enabled": False,
|
|
172
|
-
"approved": False,
|
|
173
|
-
"approved_at": None,
|
|
174
|
-
"approved_by": None,
|
|
175
|
-
"scopes": ["Downloads", "Documents", "Repositories"],
|
|
176
|
-
"activities": [],
|
|
177
|
-
"notice": "Local Computer Memory is OFF by default and requires explicit approval.",
|
|
178
|
-
},
|
|
179
|
-
"timeline": [],
|
|
180
|
-
}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
"""Helper utilities extracted from the monolithic WorkspaceOSStore module.
|
|
2
|
-
|
|
3
|
-
These are internal (_-prefixed) helpers for JSON handling, slugging, and
|
|
4
|
-
timeline data. Moving them keeps workspace_os.py focused on the store class
|
|
5
|
-
and public constants while preserving exact behavior.
|
|
6
|
-
"""
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
import json
|
|
10
|
-
import shutil
|
|
11
|
-
from pathlib import Path
|
|
12
|
-
from typing import Any, Dict, List
|
|
13
|
-
|
|
14
|
-
from .io_utils import (
|
|
15
|
-
atomic_write_json as _atomic_write_json, # noqa: F401 - legacy helper re-export
|
|
16
|
-
)
|
|
17
|
-
from .io_utils import parse_iso as _parse_iso # noqa: F401 - legacy helper re-export
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class WorkspaceStoreMixin:
|
|
21
|
-
"""A collaborator that reads and writes through ``WorkspaceOSStore``.
|
|
22
|
-
|
|
23
|
-
The store was decomposed into managers that each own one branch of the state
|
|
24
|
-
document, and every one of them needs the same two things: a reference to the
|
|
25
|
-
store, and for anything it does not implement itself (``load_state``,
|
|
26
|
-
``_scoped``, ``record_timeline_event``) to reach the store instead of raising
|
|
27
|
-
``AttributeError``. Four managers wrote that out identically; the pair lives
|
|
28
|
-
here so a fifth cannot invent a third spelling of it.
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
def __init__(self, store: Any) -> None:
|
|
32
|
-
self._store = store
|
|
33
|
-
|
|
34
|
-
def __getattr__(self, name: str) -> Any:
|
|
35
|
-
# Only reached for attributes this manager does not define, so the
|
|
36
|
-
# store is the answer for every state-document operation.
|
|
37
|
-
return getattr(self._store, name)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def graph_scope_kwargs(workspace_id: Any) -> Dict[str, Any]:
|
|
41
|
-
"""The scoped-read kwargs the graph store expects (house pattern).
|
|
42
|
-
|
|
43
|
-
``workspace_id is None`` means "unscoped caller": it reads everything it is
|
|
44
|
-
allowed to, legacy rows that predate workspaces included. A named workspace
|
|
45
|
-
reads only that workspace and never the legacy pool — which is the whole
|
|
46
|
-
isolation guarantee, so it is stated once.
|
|
47
|
-
"""
|
|
48
|
-
return {
|
|
49
|
-
"allowed_workspaces": {workspace_id} if workspace_id is not None else None,
|
|
50
|
-
"include_legacy_global": workspace_id is None,
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def _safe_slug(raw: str) -> str:
|
|
55
|
-
value = "".join(ch if ch.isalnum() or ch in "-_." else "-" for ch in str(raw or "").strip())
|
|
56
|
-
value = "-".join(part for part in value.split("-") if part)
|
|
57
|
-
return (value or "item")[:96]
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def _json_hash(value: Any) -> str:
|
|
61
|
-
import hashlib
|
|
62
|
-
|
|
63
|
-
payload = json.dumps(value, ensure_ascii=False, sort_keys=True, default=str)
|
|
64
|
-
return hashlib.sha256(payload.encode("utf-8", errors="replace")).hexdigest()
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def _deep_merge(default: Any, loaded: Any) -> Any:
|
|
68
|
-
if isinstance(default, dict) and isinstance(loaded, dict):
|
|
69
|
-
merged = {key: _deep_merge(value, loaded.get(key)) for key, value in default.items()}
|
|
70
|
-
for key, value in loaded.items():
|
|
71
|
-
if key not in merged:
|
|
72
|
-
merged[key] = value
|
|
73
|
-
return merged
|
|
74
|
-
if loaded is None:
|
|
75
|
-
return default
|
|
76
|
-
return loaded
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def _listify(value: Any) -> List[Any]:
|
|
80
|
-
return value if isinstance(value, list) else []
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def _file_size(path: Path) -> int:
|
|
84
|
-
try:
|
|
85
|
-
return path.stat().st_size
|
|
86
|
-
except Exception:
|
|
87
|
-
return 0
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def remove_skill_directory(skills_dir: Path, skill: str) -> Dict[str, Any]:
|
|
91
|
-
"""Remove an installed skill directory after caller has performed auth checks.
|
|
92
|
-
|
|
93
|
-
Moved here from workspace_os.py for smaller focused surface.
|
|
94
|
-
"""
|
|
95
|
-
safe_name = _safe_slug(skill)
|
|
96
|
-
target = (skills_dir / safe_name).resolve()
|
|
97
|
-
root = skills_dir.resolve()
|
|
98
|
-
if not str(target).startswith(str(root)):
|
|
99
|
-
raise ValueError("invalid skill path")
|
|
100
|
-
if not target.exists() or not target.is_dir():
|
|
101
|
-
raise FileNotFoundError(skill)
|
|
102
|
-
shutil.rmtree(target)
|
|
103
|
-
return {"status": "ok", "skill": safe_name, "removed_path": str(target)}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
"""Workspace permission and role logic extracted from WorkspaceOSStore.
|
|
2
|
-
|
|
3
|
-
Provides pure functions + a small PermissionManager for composition.
|
|
4
|
-
All behavior preserved; main store continues to expose the same public methods.
|
|
5
|
-
"""
|
|
6
|
-
from __future__ import annotations
|
|
7
|
-
|
|
8
|
-
from typing import Any, Dict, Optional
|
|
9
|
-
|
|
10
|
-
from .timeutil import now_iso as _now
|
|
11
|
-
from .workspace_os_utils import _listify
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
# Avoid circular at import time: pull constants lazily from parent module.
|
|
15
|
-
def _get_role_permissions():
|
|
16
|
-
from .workspace_os import ROLE_PERMISSIONS
|
|
17
|
-
return ROLE_PERMISSIONS
|
|
18
|
-
|
|
19
|
-
def _get_workspace_roles():
|
|
20
|
-
from .workspace_os import WORKSPACE_ROLES
|
|
21
|
-
return WORKSPACE_ROLES
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def _member_role(ws: Dict[str, Any], user_id: Optional[str]) -> Optional[str]:
|
|
25
|
-
if ws.get("type") == "personal":
|
|
26
|
-
return "owner"
|
|
27
|
-
owner = ws.get("owner_user_id")
|
|
28
|
-
if not owner and not user_id:
|
|
29
|
-
return "owner"
|
|
30
|
-
if user_id and user_id == owner:
|
|
31
|
-
return "owner"
|
|
32
|
-
for member in _listify(ws.get("members")):
|
|
33
|
-
if member.get("user_id") == user_id:
|
|
34
|
-
return member.get("role")
|
|
35
|
-
return None
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def has_permission(ws_or_store: Any, workspace_id: str, user_id: Optional[str], permission: str) -> bool:
|
|
39
|
-
"""Works both as standalone or delegated."""
|
|
40
|
-
if hasattr(ws_or_store, "load_state"):
|
|
41
|
-
# called as method on store
|
|
42
|
-
ws = (ws_or_store.load_state().get("workspaces") or {}).get(workspace_id)
|
|
43
|
-
else:
|
|
44
|
-
ws = ws_or_store
|
|
45
|
-
if not ws:
|
|
46
|
-
return False
|
|
47
|
-
role = _member_role(ws, user_id)
|
|
48
|
-
if role is None:
|
|
49
|
-
return False
|
|
50
|
-
return permission in _get_role_permissions().get(role, set())
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
class WorkspacePermissionManager:
|
|
54
|
-
"""Composable permission manager."""
|
|
55
|
-
|
|
56
|
-
def __init__(self, store: Any):
|
|
57
|
-
self._store = store
|
|
58
|
-
|
|
59
|
-
def get_member_role(self, workspace_id: str, user_id: Optional[str]) -> Optional[str]:
|
|
60
|
-
ws = (self._store.load_state().get("workspaces") or {}).get(workspace_id)
|
|
61
|
-
if not ws:
|
|
62
|
-
raise FileNotFoundError(workspace_id)
|
|
63
|
-
return _member_role(ws, user_id)
|
|
64
|
-
|
|
65
|
-
def has_permission(self, workspace_id: str, user_id: Optional[str], permission: str) -> bool:
|
|
66
|
-
try:
|
|
67
|
-
role = self.get_member_role(workspace_id, user_id)
|
|
68
|
-
except FileNotFoundError:
|
|
69
|
-
return False
|
|
70
|
-
if role is None:
|
|
71
|
-
return False
|
|
72
|
-
return permission in _get_role_permissions().get(role, set())
|
|
73
|
-
|
|
74
|
-
def require_permission(self, ws: Dict[str, Any], actor: Optional[str], permission: str) -> None:
|
|
75
|
-
role = _member_role(ws, actor)
|
|
76
|
-
if role is None or permission not in _get_role_permissions().get(role, set()):
|
|
77
|
-
raise PermissionError(
|
|
78
|
-
f"'{actor or 'anonymous'}' lacks '{permission}' on workspace '{ws.get('workspace_id')}'"
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
def add_member(self, workspace_id: str, *, user_id: str, role: str = "member", actor: Optional[str] = None) -> Dict[str, Any]:
|
|
82
|
-
if role not in _get_workspace_roles():
|
|
83
|
-
raise ValueError(f"unknown role: {role}")
|
|
84
|
-
if not str(user_id or "").strip():
|
|
85
|
-
raise ValueError("user_id is required")
|
|
86
|
-
state = self._store.load_state()
|
|
87
|
-
ws = self._store._load_org(state, workspace_id)
|
|
88
|
-
self.require_permission(ws, actor, "manage_members")
|
|
89
|
-
members = ws.setdefault("members", [])
|
|
90
|
-
existing = next((m for m in members if m.get("user_id") == user_id), None)
|
|
91
|
-
if existing:
|
|
92
|
-
existing["role"] = role
|
|
93
|
-
existing["updated_at"] = _now()
|
|
94
|
-
else:
|
|
95
|
-
members.append({"user_id": user_id, "role": role, "added_at": _now()})
|
|
96
|
-
ws["updated_at"] = _now()
|
|
97
|
-
self._store.save_state(state)
|
|
98
|
-
self._store.record_timeline_event("workspace", "member_added", {"workspace_id": workspace_id, "user_id": user_id, "role": role})
|
|
99
|
-
return self._store._workspace_public(ws, actor)
|
|
100
|
-
|
|
101
|
-
# add thin wrappers for update/remove if needed by store
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
"""Plugins, marketplace templates, and skill management extracted from WorkspaceOSStore.
|
|
2
|
-
|
|
3
|
-
Provides PluginManager for composition.
|
|
4
|
-
"""
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
from typing import Any, Dict, Optional
|
|
8
|
-
|
|
9
|
-
from .timeutil import now_iso as _now
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class WorkspacePluginManager:
|
|
13
|
-
"""Composable plugin + marketplace manager."""
|
|
14
|
-
|
|
15
|
-
def __init__(self, store: Any):
|
|
16
|
-
self._store = store
|
|
17
|
-
|
|
18
|
-
def list_plugin_registry(self) -> Dict[str, Any]:
|
|
19
|
-
return dict(self._store.load_state().get("plugin_registry") or {})
|
|
20
|
-
|
|
21
|
-
def set_plugin_enabled(self, plugin_id: str, enabled: bool) -> Dict[str, Any]:
|
|
22
|
-
state = self._store.load_state()
|
|
23
|
-
entry = state.setdefault("plugin_registry", {}).setdefault(plugin_id, {"id": plugin_id})
|
|
24
|
-
entry["enabled"] = bool(enabled)
|
|
25
|
-
entry["updated_at"] = _now()
|
|
26
|
-
self._store.save_state(state)
|
|
27
|
-
self._store.record_timeline_event("plugins", "plugin_toggled", {"plugin": plugin_id, "enabled": enabled})
|
|
28
|
-
return entry
|
|
29
|
-
|
|
30
|
-
def mark_plugin_installed(self, plugin_id: str, *, version: str = "0.0.0", metadata: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
31
|
-
state = self._store.load_state()
|
|
32
|
-
entry = state.setdefault("plugin_registry", {}).setdefault(plugin_id, {"id": plugin_id})
|
|
33
|
-
entry.update({
|
|
34
|
-
"id": plugin_id,
|
|
35
|
-
"installed": True,
|
|
36
|
-
"enabled": entry.get("enabled", True),
|
|
37
|
-
"version": version,
|
|
38
|
-
"install_status": "ready",
|
|
39
|
-
"validation_status": "valid",
|
|
40
|
-
"metadata": metadata or entry.get("metadata") or {},
|
|
41
|
-
"updated_at": _now(),
|
|
42
|
-
})
|
|
43
|
-
self._store.save_state(state)
|
|
44
|
-
self._store.record_timeline_event("plugins", "plugin_installed", {"plugin": plugin_id, "version": version})
|
|
45
|
-
return entry
|
|
46
|
-
|
|
47
|
-
def mark_plugin_uninstalled(self, plugin_id: str) -> Dict[str, Any]:
|
|
48
|
-
state = self._store.load_state()
|
|
49
|
-
entry = state.setdefault("plugin_registry", {}).setdefault(plugin_id, {"id": plugin_id})
|
|
50
|
-
entry.update({"installed": False, "enabled": False, "updated_at": _now()})
|
|
51
|
-
self._store.save_state(state)
|
|
52
|
-
self._store.record_timeline_event("plugins", "plugin_uninstalled", {"plugin": plugin_id})
|
|
53
|
-
return {"status": "ok", "plugin_id": plugin_id, "registry": entry}
|
|
54
|
-
|
|
55
|
-
# Marketplace templates
|
|
56
|
-
@staticmethod
|
|
57
|
-
def _template_registry_key(kind: str, template_id: str, workspace_id: str) -> str:
|
|
58
|
-
base = f"{kind}:{template_id}"
|
|
59
|
-
return base if workspace_id == "personal" else f"{workspace_id}:{base}"
|
|
60
|
-
|
|
61
|
-
def list_template_registry(self, workspace_id: Optional[str] = None) -> Dict[str, Any]:
|
|
62
|
-
state = self._store.load_state()
|
|
63
|
-
registry = dict(state.get("template_registry") or {})
|
|
64
|
-
if workspace_id is None:
|
|
65
|
-
return registry
|
|
66
|
-
scope = self._store._resolve_scope(workspace_id, state)
|
|
67
|
-
return {
|
|
68
|
-
key: value
|
|
69
|
-
for key, value in registry.items()
|
|
70
|
-
if self._store._record_workspace(value) == scope
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
def mark_template_installed(
|
|
74
|
-
self,
|
|
75
|
-
*,
|
|
76
|
-
kind: str,
|
|
77
|
-
template_id: str,
|
|
78
|
-
version: str = "1.0.0",
|
|
79
|
-
metadata: Optional[Dict[str, Any]] = None,
|
|
80
|
-
workspace_id: Optional[str] = None,
|
|
81
|
-
) -> Dict[str, Any]:
|
|
82
|
-
state = self._store.load_state()
|
|
83
|
-
scope = self._store._resolve_scope(workspace_id, state)
|
|
84
|
-
key = self._template_registry_key(kind, template_id, scope)
|
|
85
|
-
entry = state.setdefault("template_registry", {}).setdefault(key, {"id": template_id, "kind": kind})
|
|
86
|
-
entry.update({
|
|
87
|
-
"id": template_id,
|
|
88
|
-
"kind": kind,
|
|
89
|
-
"version": version,
|
|
90
|
-
"installed": True,
|
|
91
|
-
"workspace_id": scope,
|
|
92
|
-
"metadata": metadata or entry.get("metadata") or {},
|
|
93
|
-
"updated_at": _now(),
|
|
94
|
-
})
|
|
95
|
-
self._store.save_state(state)
|
|
96
|
-
self._store.record_timeline_event("marketplace", "template_installed", {"kind": kind, "template_id": template_id}, workspace_id=scope)
|
|
97
|
-
return entry
|