@hybridlabor-api/aos 4.4.1 → 4.4.2-beta.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/.agents/skills/firecrawl/SKILL.md +149 -0
- package/.agents/skills/firecrawl/rules/install.md +82 -0
- package/.agents/skills/firecrawl/rules/security.md +26 -0
- package/.agents/skills/firecrawl-agent/SKILL.md +58 -0
- package/.agents/skills/firecrawl-build/SKILL.md +39 -0
- package/.agents/skills/firecrawl-build-interact/SKILL.md +68 -0
- package/.agents/skills/firecrawl-build-onboarding/SKILL.md +103 -0
- package/.agents/skills/firecrawl-build-onboarding/references/auth-flow.md +39 -0
- package/.agents/skills/firecrawl-build-onboarding/references/project-setup.md +20 -0
- package/.agents/skills/firecrawl-build-onboarding/references/sdk-installation.md +17 -0
- package/.agents/skills/firecrawl-build-scrape/SKILL.md +69 -0
- package/.agents/skills/firecrawl-build-search/SKILL.md +69 -0
- package/.agents/skills/firecrawl-crawl/SKILL.md +59 -0
- package/.agents/skills/firecrawl-download/SKILL.md +70 -0
- package/.agents/skills/firecrawl-interact/SKILL.md +84 -0
- package/.agents/skills/firecrawl-map/SKILL.md +51 -0
- package/.agents/skills/firecrawl-scrape/SKILL.md +69 -0
- package/.agents/skills/firecrawl-search/SKILL.md +60 -0
- package/CLAUDE.md +573 -0
- package/README.de.md +0 -8
- package/README.md +0 -8
- package/README.pt.md +0 -8
- package/assets/brand/ao-ant-mark.svg +91 -0
- package/assets/brand/bdb-core-mark.svg +34 -0
- package/assets/brand/heimdall-guardian-mark.svg +16 -0
- package/assets/brand/memb-crystal-mark.svg +18 -0
- package/bin/aos-config.mjs +89 -0
- package/bin/aos-dashboard.mjs +608 -0
- package/bin/aos-uninstall.mjs +227 -0
- package/docs/sessions/audit-2026-09-14-silent-failures.md +114 -0
- package/docs/skills_table.md +0 -3
- package/installer.js +387 -237
- package/mcps/RhinoMCP/cc-plugin/.claude/settings.json +10 -0
- package/mcps/after-effects-mcp/build/index.js +840 -0
- package/mcps/after-effects-mcp/build/scripts/applyEffect.jsx +153 -0
- package/mcps/after-effects-mcp/build/scripts/applyEffectTemplate.jsx +218 -0
- package/mcps/after-effects-mcp/build/scripts/createComposition.jsx +71 -0
- package/mcps/after-effects-mcp/build/scripts/createShapeLayer.jsx +147 -0
- package/mcps/after-effects-mcp/build/scripts/createSolidLayer.jsx +114 -0
- package/mcps/after-effects-mcp/build/scripts/createTextLayer.jsx +115 -0
- package/mcps/after-effects-mcp/build/scripts/getLayerInfo.jsx +192 -0
- package/mcps/after-effects-mcp/build/scripts/getProjectInfo.jsx +90 -0
- package/mcps/after-effects-mcp/build/scripts/listCompositions.jsx +50 -0
- package/mcps/after-effects-mcp/build/scripts/mcp-bridge-auto.jsx +1773 -0
- package/mcps/after-effects-mcp/build/scripts/setLayerProperties.jsx +160 -0
- package/mcps/computer-use-mcp/dist/client.d.ts +150 -0
- package/mcps/computer-use-mcp/dist/client.js +136 -0
- package/mcps/computer-use-mcp/dist/entrypoint.d.ts +16 -0
- package/mcps/computer-use-mcp/dist/entrypoint.js +26 -0
- package/mcps/computer-use-mcp/dist/native.d.ts +212 -0
- package/mcps/computer-use-mcp/dist/native.js +50 -0
- package/mcps/computer-use-mcp/dist/server.d.ts +32 -0
- package/mcps/computer-use-mcp/dist/server.js +342 -0
- package/mcps/computer-use-mcp/dist/session.d.ts +101 -0
- package/mcps/computer-use-mcp/dist/session.js +2372 -0
- package/package.json +13 -4
- package/skills/global_config/aos-project-init/SKILL.md +97 -130
- package/skills/global_config/aos-project-init/assets/openwikiignore.template +62 -0
- package/skills/global_config/aos-project-init/scripts/aos-project-doctor.mjs +38 -1
- package/skills/global_config/aos-setup/SKILL.md +98 -8
- package/skills/global_config/aos-setup/scripts/aos-doctor.mjs +21 -2
- package/skills/global_config/ask-tim/SKILL.md +2 -7
- package/skills/global_config/openwiki-skill/scripts/openwiki_daemon.py +65 -12
- package/bin/setup-saas.mjs +0 -792
- package/mcps/blender-mcp-server/.dockerignore +0 -19
- package/mcps/blender-mcp-server/.github/workflows/ci.yml +0 -67
- package/mcps/blender-mcp-server/.github/workflows/publish-pypi.yml +0 -54
- package/mcps/blender-mcp-server/CHANGELOG.md +0 -64
- package/mcps/blender-mcp-server/CONTRIBUTING.md +0 -107
- package/mcps/blender-mcp-server/Dockerfile +0 -19
- package/mcps/blender-mcp-server/LICENSE +0 -21
- package/mcps/blender-mcp-server/README.md +0 -409
- package/mcps/blender-mcp-server/addon/__init__.py +0 -1440
- package/mcps/blender-mcp-server/addon/models.py +0 -223
- package/mcps/blender-mcp-server/pyproject.toml +0 -120
- package/mcps/blender-mcp-server/scripts/blender_bridge_request.py +0 -71
- package/mcps/blender-mcp-server/scripts/blender_create_test_cube.py +0 -49
- package/mcps/blender-mcp-server/scripts/blender_scene_info.py +0 -38
- package/mcps/blender-mcp-server/scripts/build_addon_zip.sh +0 -29
- package/mcps/blender-mcp-server/scripts/demos/README.md +0 -186
- package/mcps/blender-mcp-server/scripts/demos/dam_break_scene.py +0 -276
- package/mcps/blender-mcp-server/scripts/demos/open_dam_break_gui.py +0 -33
- package/mcps/blender-mcp-server/scripts/demos/pipe_movement_study.py +0 -518
- package/mcps/blender-mcp-server/scripts/demos/pipe_pressure_failure_scene.py +0 -806
- package/mcps/blender-mcp-server/scripts/demos/procedural_dam_break_scene.py +0 -600
- package/mcps/blender-mcp-server/scripts/demos/run_dam_break.py +0 -510
- package/mcps/blender-mcp-server/scripts/launch_blender_gui.py +0 -41
- package/mcps/blender-mcp-server/scripts/library/README.md +0 -64
- package/mcps/blender-mcp-server/scripts/library/apply_transforms.py +0 -46
- package/mcps/blender-mcp-server/scripts/library/camera.py +0 -51
- package/mcps/blender-mcp-server/scripts/library/collections.py +0 -65
- package/mcps/blender-mcp-server/scripts/library/create_mesh.py +0 -41
- package/mcps/blender-mcp-server/scripts/library/effector.py +0 -48
- package/mcps/blender-mcp-server/scripts/library/fluid_domain.py +0 -80
- package/mcps/blender-mcp-server/scripts/library/fluid_inflow.py +0 -98
- package/mcps/blender-mcp-server/scripts/library/frame_range.py +0 -35
- package/mcps/blender-mcp-server/scripts/library/keyframes.py +0 -59
- package/mcps/blender-mcp-server/scripts/library/rigid_body.py +0 -52
- package/mcps/blender-mcp-server/scripts/library/save_blend.py +0 -40
- package/mcps/blender-mcp-server/scripts/server_start.sh +0 -26
- package/mcps/blender-mcp-server/src/blender_mcp_server/__init__.py +0 -3
- package/mcps/blender-mcp-server/src/blender_mcp_server/headless.py +0 -330
- package/mcps/blender-mcp-server/src/blender_mcp_server/server.py +0 -606
- package/mcps/davinci-mcp-professional/.bandit +0 -35
- package/mcps/davinci-mcp-professional/.claude/commands/security-review.md +0 -191
- package/mcps/davinci-mcp-professional/.claude/settings.json +0 -1
- package/mcps/davinci-mcp-professional/.editorconfig +0 -27
- package/mcps/davinci-mcp-professional/.gitattributes +0 -207
- package/mcps/davinci-mcp-professional/.github/CODEOWNERS +0 -2
- package/mcps/davinci-mcp-professional/.github/ISSUE_TEMPLATE/bug_report.md +0 -33
- package/mcps/davinci-mcp-professional/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
- package/mcps/davinci-mcp-professional/.github/PULL_REQUEST_TEMPLATE.md +0 -20
- package/mcps/davinci-mcp-professional/.github/SECURITY.md +0 -97
- package/mcps/davinci-mcp-professional/.github/dependabot.yml +0 -27
- package/mcps/davinci-mcp-professional/.github/workflows/ci.yml +0 -39
- package/mcps/davinci-mcp-professional/ATTRIBUTION.md +0 -4
- package/mcps/davinci-mcp-professional/AUTHORS.md +0 -9
- package/mcps/davinci-mcp-professional/BUGS.md +0 -55
- package/mcps/davinci-mcp-professional/CLAUDE.md +0 -229
- package/mcps/davinci-mcp-professional/CONTRIBUTING.md +0 -51
- package/mcps/davinci-mcp-professional/COPYING.md +0 -228
- package/mcps/davinci-mcp-professional/Doxyfile +0 -379
- package/mcps/davinci-mcp-professional/README.md +0 -143
- package/mcps/davinci-mcp-professional/SECURITY.md +0 -40
- package/mcps/davinci-mcp-professional/USING.md +0 -301
- package/mcps/davinci-mcp-professional/VERSION.md +0 -13
- package/mcps/davinci-mcp-professional/build.py +0 -169
- package/mcps/davinci-mcp-professional/claude_desktop_config_template.json +0 -11
- package/mcps/davinci-mcp-professional/hooks/ci-check.sh +0 -29
- package/mcps/davinci-mcp-professional/hooks/pre-push +0 -46
- package/mcps/davinci-mcp-professional/main.py +0 -40
- package/mcps/davinci-mcp-professional/mcp_server.py +0 -30
- package/mcps/davinci-mcp-professional/pyproject.toml +0 -115
- package/mcps/davinci-mcp-professional/security_audit.py +0 -379
- package/mcps/davinci-mcp-professional/src/davinci_mcp/__init__.py +0 -19
- package/mcps/davinci-mcp-professional/src/davinci_mcp/cli.py +0 -138
- package/mcps/davinci-mcp-professional/src/davinci_mcp/resolve_client.py +0 -342
- package/mcps/davinci-mcp-professional/src/davinci_mcp/resources/__init__.py +0 -60
- package/mcps/davinci-mcp-professional/src/davinci_mcp/server.py +0 -185
- package/mcps/davinci-mcp-professional/src/davinci_mcp/tools/__init__.py +0 -146
- package/mcps/davinci-mcp-professional/src/davinci_mcp/types.py +0 -125
- package/mcps/davinci-mcp-professional/src/davinci_mcp/utils/__init__.py +0 -19
- package/mcps/davinci-mcp-professional/src/davinci_mcp/utils/platform.py +0 -239
- package/mcps/davinci-mcp-professional/test.py +0 -186
- package/mcps/davinci-mcp-professional/uv.lock +0 -2073
- package/mcps/davinci-resolve-mcp/.claude/skills/media-analysis.md +0 -44
- package/mcps/davinci-resolve-mcp/.clinerules +0 -17
- package/mcps/davinci-resolve-mcp/.cursorrules +0 -17
- package/mcps/davinci-resolve-mcp/.github/copilot-instructions.md +0 -17
- package/mcps/davinci-resolve-mcp/.github/workflows/npm-publish.yml +0 -109
- package/mcps/davinci-resolve-mcp/.windsurfrules +0 -17
- package/mcps/davinci-resolve-mcp/AGENTS.md +0 -114
- package/mcps/davinci-resolve-mcp/CHANGELOG.md +0 -2648
- package/mcps/davinci-resolve-mcp/CLAUDE.md +0 -15
- package/mcps/davinci-resolve-mcp/LICENSE +0 -21
- package/mcps/davinci-resolve-mcp/README.md +0 -173
- package/mcps/davinci-resolve-mcp/SECURITY.md +0 -53
- package/mcps/davinci-resolve-mcp/bin/davinci-resolve-mcp.mjs +0 -450
- package/mcps/davinci-resolve-mcp/examples/README.md +0 -53
- package/mcps/davinci-resolve-mcp/examples/markers/README.md +0 -81
- package/mcps/davinci-resolve-mcp/examples/media/README.md +0 -94
- package/mcps/davinci-resolve-mcp/examples/timeline/README.md +0 -98
- package/mcps/davinci-resolve-mcp/install.py +0 -1687
- package/mcps/davinci-resolve-mcp/package.json +0 -52
- package/mcps/davinci-resolve-mcp/release-notes/v2.22.0.md +0 -51
- package/mcps/davinci-resolve-mcp/release-notes/v2.23.0.md +0 -51
- package/mcps/davinci-resolve-mcp/release-notes/v2.23.1.md +0 -35
- package/mcps/davinci-resolve-mcp/release-notes/v2.24.1.md +0 -32
- package/mcps/davinci-resolve-mcp/scripts/audit_api_parity.py +0 -275
- package/mcps/davinci-resolve-mcp/scripts/audit_readwrite_symmetry.py +0 -80
- package/mcps/davinci-resolve-mcp/scripts/doctor.py +0 -227
- package/mcps/davinci-resolve-mcp/scripts/gen_api_limitations.py +0 -144
- package/mcps/davinci-resolve-mcp/scripts/live_media_analysis_polish_probe.py +0 -65
- package/mcps/davinci-resolve-mcp/scripts/measure_bridge_cost.py +0 -65
- package/mcps/davinci-resolve-mcp/scripts/regen_panel_screenshots.py +0 -76
- package/mcps/davinci-resolve-mcp/src/__init__.py +0 -3
- package/mcps/davinci-resolve-mcp/src/analysis_dashboard.py +0 -15505
- package/mcps/davinci-resolve-mcp/src/batch_cli.py +0 -540
- package/mcps/davinci-resolve-mcp/src/control_panel.py +0 -13
- package/mcps/davinci-resolve-mcp/src/granular/__init__.py +0 -17
- package/mcps/davinci-resolve-mcp/src/granular/common.py +0 -741
- package/mcps/davinci-resolve-mcp/src/granular/folder.py +0 -420
- package/mcps/davinci-resolve-mcp/src/granular/gallery.py +0 -306
- package/mcps/davinci-resolve-mcp/src/granular/graph.py +0 -309
- package/mcps/davinci-resolve-mcp/src/granular/media_pool.py +0 -679
- package/mcps/davinci-resolve-mcp/src/granular/media_pool_item.py +0 -1020
- package/mcps/davinci-resolve-mcp/src/granular/media_storage.py +0 -179
- package/mcps/davinci-resolve-mcp/src/granular/project.py +0 -1654
- package/mcps/davinci-resolve-mcp/src/granular/resolve_control.py +0 -538
- package/mcps/davinci-resolve-mcp/src/granular/timeline.py +0 -1075
- package/mcps/davinci-resolve-mcp/src/granular/timeline_item.py +0 -2251
- package/mcps/davinci-resolve-mcp/src/resolve_mcp_server.py +0 -43
- package/mcps/davinci-resolve-mcp/src/server.py +0 -24116
- package/mcps/davinci-resolve-mcp/src/utils/__init__.py +0 -3
- package/mcps/davinci-resolve-mcp/src/utils/actor_identity.py +0 -46
- package/mcps/davinci-resolve-mcp/src/utils/analysis_caps.py +0 -678
- package/mcps/davinci-resolve-mcp/src/utils/analysis_memory.py +0 -755
- package/mcps/davinci-resolve-mcp/src/utils/analysis_runs.py +0 -307
- package/mcps/davinci-resolve-mcp/src/utils/analysis_store.py +0 -945
- package/mcps/davinci-resolve-mcp/src/utils/api_truth.py +0 -525
- package/mcps/davinci-resolve-mcp/src/utils/app_control.py +0 -319
- package/mcps/davinci-resolve-mcp/src/utils/audio_fairlight_live_probe.py +0 -263
- package/mcps/davinci-resolve-mcp/src/utils/brain_edits.py +0 -387
- package/mcps/davinci-resolve-mcp/src/utils/bridge_metrics.py +0 -76
- package/mcps/davinci-resolve-mcp/src/utils/cdl.py +0 -20
- package/mcps/davinci-resolve-mcp/src/utils/clip_query.py +0 -85
- package/mcps/davinci-resolve-mcp/src/utils/cloud_operations.py +0 -192
- package/mcps/davinci-resolve-mcp/src/utils/color_grade_live_probe.py +0 -444
- package/mcps/davinci-resolve-mcp/src/utils/contracts.py +0 -102
- package/mcps/davinci-resolve-mcp/src/utils/cut_ir.py +0 -115
- package/mcps/davinci-resolve-mcp/src/utils/dctl_templates.py +0 -368
- package/mcps/davinci-resolve-mcp/src/utils/deep_vision.py +0 -643
- package/mcps/davinci-resolve-mcp/src/utils/destructive_hook.py +0 -606
- package/mcps/davinci-resolve-mcp/src/utils/edit_engine.py +0 -737
- package/mcps/davinci-resolve-mcp/src/utils/embeddings.py +0 -922
- package/mcps/davinci-resolve-mcp/src/utils/entities.py +0 -579
- package/mcps/davinci-resolve-mcp/src/utils/extension_authoring_live_probe.py +0 -292
- package/mcps/davinci-resolve-mcp/src/utils/failure_tracker.py +0 -119
- package/mcps/davinci-resolve-mcp/src/utils/fuse_templates.py +0 -1968
- package/mcps/davinci-resolve-mcp/src/utils/fusion_composition_live_probe.py +0 -284
- package/mcps/davinci-resolve-mcp/src/utils/fusion_group_settings.py +0 -334
- package/mcps/davinci-resolve-mcp/src/utils/layout_presets.py +0 -333
- package/mcps/davinci-resolve-mcp/src/utils/mcp_stdio.py +0 -32
- package/mcps/davinci-resolve-mcp/src/utils/mcp_transport.py +0 -128
- package/mcps/davinci-resolve-mcp/src/utils/media_analysis.py +0 -7690
- package/mcps/davinci-resolve-mcp/src/utils/media_analysis_jobs.py +0 -805
- package/mcps/davinci-resolve-mcp/src/utils/media_pool_changes.py +0 -121
- package/mcps/davinci-resolve-mcp/src/utils/media_pool_ingest_live_probe.py +0 -592
- package/mcps/davinci-resolve-mcp/src/utils/multicam.py +0 -393
- package/mcps/davinci-resolve-mcp/src/utils/object_inspection.py +0 -301
- package/mcps/davinci-resolve-mcp/src/utils/page_lock.py +0 -75
- package/mcps/davinci-resolve-mcp/src/utils/platform.py +0 -157
- package/mcps/davinci-resolve-mcp/src/utils/proc.py +0 -26
- package/mcps/davinci-resolve-mcp/src/utils/project_cleanup.py +0 -73
- package/mcps/davinci-resolve-mcp/src/utils/project_lifecycle_live_probe.py +0 -376
- package/mcps/davinci-resolve-mcp/src/utils/project_lint.py +0 -131
- package/mcps/davinci-resolve-mcp/src/utils/project_properties.py +0 -601
- package/mcps/davinci-resolve-mcp/src/utils/project_spec.py +0 -459
- package/mcps/davinci-resolve-mcp/src/utils/readback.py +0 -91
- package/mcps/davinci-resolve-mcp/src/utils/render_deliver_live_probe.py +0 -384
- package/mcps/davinci-resolve-mcp/src/utils/resolve_ai_governance.py +0 -214
- package/mcps/davinci-resolve-mcp/src/utils/resolve_ai_ledger.py +0 -244
- package/mcps/davinci-resolve-mcp/src/utils/resolve_busy.py +0 -171
- package/mcps/davinci-resolve-mcp/src/utils/resolve_connection.py +0 -77
- package/mcps/davinci-resolve-mcp/src/utils/review_annotation_live_probe.py +0 -352
- package/mcps/davinci-resolve-mcp/src/utils/script_templates.py +0 -1193
- package/mcps/davinci-resolve-mcp/src/utils/shot_relationships.py +0 -544
- package/mcps/davinci-resolve-mcp/src/utils/structural_diff.py +0 -175
- package/mcps/davinci-resolve-mcp/src/utils/sync_detection.py +0 -889
- package/mcps/davinci-resolve-mcp/src/utils/timeline_brain_db.py +0 -826
- package/mcps/davinci-resolve-mcp/src/utils/timeline_conform_live_probe.py +0 -280
- package/mcps/davinci-resolve-mcp/src/utils/timeline_kernel_live_probe.py +0 -1092
- package/mcps/davinci-resolve-mcp/src/utils/timeline_kernel_probe.py +0 -185
- package/mcps/davinci-resolve-mcp/src/utils/timeline_title_text.py +0 -87
- package/mcps/davinci-resolve-mcp/src/utils/timeline_versioning.py +0 -730
- package/mcps/davinci-resolve-mcp/src/utils/update_check.py +0 -685
- package/mcps/vectorworks-mcp/.dockerignore +0 -8
- package/mcps/vectorworks-mcp/Dockerfile +0 -28
- package/mcps/vectorworks-mcp/README.md +0 -156
- package/mcps/vectorworks-mcp/app/__init__.py +0 -2
- package/mcps/vectorworks-mcp/app/api.py +0 -52
- package/mcps/vectorworks-mcp/app/chunking.py +0 -56
- package/mcps/vectorworks-mcp/app/config.py +0 -29
- package/mcps/vectorworks-mcp/app/embeddings.py +0 -28
- package/mcps/vectorworks-mcp/app/indexer.py +0 -106
- package/mcps/vectorworks-mcp/app/main.py +0 -33
- package/mcps/vectorworks-mcp/app/mcp_server.py +0 -71
- package/mcps/vectorworks-mcp/app/search.py +0 -54
- package/mcps/vectorworks-mcp/app/utils.py +0 -14
- package/mcps/vectorworks-mcp/data/.gitkeep +0 -1
- package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_PluginScript.htm +0 -95
- package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_ScriptEditor.htm +0 -266
- package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_Scripting.htm +0 -106
- package/mcps/vectorworks-mcp/data/vw-app-help/VW2023_CreatingScriptedPlugins.htm +0 -327
- package/mcps/vectorworks-mcp/data/vw-app-help/VW2024_RunningScripts.htm +0 -116
- package/mcps/vectorworks-mcp/data/vw-devwiki/VS_Function_Reference_category.html +0 -2129
- package/mcps/vectorworks-mcp/data/vw-jp-ref/ObjectsSymbols.html +0 -2035
- package/mcps/vectorworks-mcp/data/vw-jp-ref/ScriptFunctionReference.html +0 -29
- package/mcps/vectorworks-mcp/design.md +0 -57
- package/mcps/vectorworks-mcp/docker-compose.yml +0 -18
- package/mcps/vectorworks-mcp/index/.gitkeep +0 -1
- package/mcps/vectorworks-mcp/index/meta.jsonl +0 -3956
- package/mcps/vectorworks-mcp/index/vw.faiss +0 -0
- package/mcps/vectorworks-mcp/requirements.txt +0 -10
- package/mcps/vectorworks-mcp/scripts/fetch_docs_minimal.sh +0 -84
- package/mcps/vectorworks-mcp/scripts/fetch_github_vectorworks.sh +0 -85
- package/mcps/vectorworks-mcp/templates/index.html +0 -40
- package/scripts/ecosystem-health-audit.js +0 -257
- package/skills/bdb-dev-os-skill/SKILL.md +0 -49
- package/skills/bdb-dev-os-skill/package.json +0 -11
- package/skills/bdbsaastraining/SKILL.md +0 -316
- package/skills/bdbsaastraining/references/exam-pool.md +0 -313
- package/skills/bdbsaastraining/references/interaction-modes.md +0 -94
- package/skills/bdbsaastraining/references/track-a-ai-agent.md +0 -111
- package/skills/bdbsaastraining/references/track-b-wordpress.md +0 -111
- package/skills/bdbsaastraining/references/track-c-mailserver.md +0 -107
- package/skills/bdbsaastraining/references/track-d-debian.md +0 -109
- package/skills/bdbsaastraining/references/track-e-custom.md +0 -83
- package/skills/bdbsaastraining/scripts/build_profile.py +0 -529
- package/skills/bdbsaastraining/scripts/generate_certificate.py +0 -161
- package/skills/bdbsaastraining/scripts/preflight_check.sh +0 -150
- package/skills/bdbsaastraining/templates/certificate_template.html +0 -508
- package/skills/global_config/bdb-ecosystem-health/SKILL.md +0 -68
- package/skills/global_config/bdbsaas-ops/SKILL.md +0 -16
- package/skills/global_config/bdbsaashost/SKILL.md +0 -125
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
"""Run-scoping for the destructive-op hook (C6 hardening).
|
|
2
|
-
|
|
3
|
-
A *run* groups a sequence of destructive operations under a single ID so that:
|
|
4
|
-
|
|
5
|
-
1. **Archives collapse correctly.** Without run scoping, every destructive call
|
|
6
|
-
without an explicit `analysis_run_id` archives separately. A single brain
|
|
7
|
-
operation that touches five clips creates five archives. With run scoping,
|
|
8
|
-
the brain calls `begin_run` once, every subsequent destructive call within
|
|
9
|
-
that run reuses the same ID, and only the first one archives — the rest log
|
|
10
|
-
brain_edits under the same archived predecessor.
|
|
11
|
-
2. **Cumulative metrics are computable.** `end_run` aggregates every brain_edit
|
|
12
|
-
for the run, captures a final timeline snapshot, and writes the rollup to
|
|
13
|
-
`analysis_runs.summary_json`. That's the row the dashboard reads to answer
|
|
14
|
-
"did this run improve the cut?"
|
|
15
|
-
3. **Provenance is tracked.** Each run records its `initiator` (e.g.
|
|
16
|
-
"control_panel", "brain.chat", "agent.batch", "user.explicit"). The
|
|
17
|
-
`brain_edits.initiator` column is populated from the active run.
|
|
18
|
-
|
|
19
|
-
Process-level state: a single `current_run_id` per process. The MCP server and
|
|
20
|
-
the dashboard are separate processes, each with their own current run; that's
|
|
21
|
-
intentional — a dashboard-initiated archive shouldn't get bundled into the
|
|
22
|
-
brain's in-flight run.
|
|
23
|
-
|
|
24
|
-
Threading: `_CURRENT_RUN` access is guarded by a lock, but a run is logically
|
|
25
|
-
single-threaded. If two requests overlap with different `begin_run` calls,
|
|
26
|
-
the second one's begin replaces the first — the first run remains in the DB
|
|
27
|
-
but no longer accumulates edits. We could enforce stack-style nesting later if
|
|
28
|
-
overlap becomes a real concern.
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
from __future__ import annotations
|
|
32
|
-
|
|
33
|
-
import json
|
|
34
|
-
import logging
|
|
35
|
-
import threading
|
|
36
|
-
import time
|
|
37
|
-
import uuid
|
|
38
|
-
from typing import Any, Dict, List, Optional
|
|
39
|
-
|
|
40
|
-
from src.utils import timeline_brain_db
|
|
41
|
-
|
|
42
|
-
logger = logging.getLogger("resolve-mcp.analysis-runs")
|
|
43
|
-
|
|
44
|
-
_LOCK = threading.Lock()
|
|
45
|
-
_CURRENT_RUN: Dict[str, Optional[str]] = {"id": None, "initiator": None, "label": None}
|
|
46
|
-
|
|
47
|
-
# B3 — Auto-run idle tracking. Bumped on every destructive call within a run.
|
|
48
|
-
_LAST_DESTRUCTIVE_AT: Dict[str, float] = {"epoch": 0.0}
|
|
49
|
-
_DEFAULT_AUTO_RUN_IDLE_TIMEOUT_S = 90.0
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def _now_iso() -> str:
|
|
53
|
-
return time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def _new_run_id() -> str:
|
|
57
|
-
return f"run_{uuid.uuid4().hex[:12]}"
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
# ── Public API ───────────────────────────────────────────────────────────────
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def begin_run(
|
|
64
|
-
*,
|
|
65
|
-
project_root: str,
|
|
66
|
-
label: Optional[str] = None,
|
|
67
|
-
initiator: Optional[str] = None,
|
|
68
|
-
analysis_run_id: Optional[str] = None,
|
|
69
|
-
) -> Dict[str, Any]:
|
|
70
|
-
"""Open a new run. Stamps `analysis_run_id` (or generates one) as the
|
|
71
|
-
process-level current run so the hook reads it automatically."""
|
|
72
|
-
run_id = analysis_run_id or _new_run_id()
|
|
73
|
-
started_at = _now_iso()
|
|
74
|
-
with timeline_brain_db.transaction(project_root) as txn:
|
|
75
|
-
txn.execute(
|
|
76
|
-
"""
|
|
77
|
-
INSERT INTO analysis_runs(id, label, initiator, started_at)
|
|
78
|
-
VALUES (?, ?, ?, ?)
|
|
79
|
-
ON CONFLICT(id) DO UPDATE SET
|
|
80
|
-
label = COALESCE(excluded.label, analysis_runs.label),
|
|
81
|
-
initiator = COALESCE(excluded.initiator, analysis_runs.initiator)
|
|
82
|
-
""",
|
|
83
|
-
(run_id, label, initiator, started_at),
|
|
84
|
-
)
|
|
85
|
-
with _LOCK:
|
|
86
|
-
# If an earlier run is still active, log a warning — the user probably
|
|
87
|
-
# forgot to end_run.
|
|
88
|
-
if _CURRENT_RUN["id"] and _CURRENT_RUN["id"] != run_id:
|
|
89
|
-
logger.warning(
|
|
90
|
-
"begin_run replacing previously-active run %s with %s (no end_run was called)",
|
|
91
|
-
_CURRENT_RUN["id"], run_id,
|
|
92
|
-
)
|
|
93
|
-
_CURRENT_RUN["id"] = run_id
|
|
94
|
-
_CURRENT_RUN["initiator"] = initiator
|
|
95
|
-
_CURRENT_RUN["label"] = label
|
|
96
|
-
return {
|
|
97
|
-
"success": True,
|
|
98
|
-
"analysis_run_id": run_id,
|
|
99
|
-
"label": label,
|
|
100
|
-
"initiator": initiator,
|
|
101
|
-
"started_at": started_at,
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
def end_run(
|
|
106
|
-
*,
|
|
107
|
-
project_root: str,
|
|
108
|
-
analysis_run_id: Optional[str] = None,
|
|
109
|
-
) -> Dict[str, Any]:
|
|
110
|
-
"""Close a run. Aggregates brain_edits + version count into `summary_json`."""
|
|
111
|
-
target_run_id: Optional[str] = analysis_run_id
|
|
112
|
-
with _LOCK:
|
|
113
|
-
active = _CURRENT_RUN["id"]
|
|
114
|
-
if target_run_id is None:
|
|
115
|
-
target_run_id = active
|
|
116
|
-
if active == target_run_id:
|
|
117
|
-
_CURRENT_RUN["id"] = None
|
|
118
|
-
_CURRENT_RUN["initiator"] = None
|
|
119
|
-
_CURRENT_RUN["label"] = None
|
|
120
|
-
if not target_run_id:
|
|
121
|
-
return {"success": False, "error": "no active run; pass analysis_run_id to end a specific run"}
|
|
122
|
-
|
|
123
|
-
conn = timeline_brain_db.connect(project_root)
|
|
124
|
-
edits = conn.execute(
|
|
125
|
-
"""
|
|
126
|
-
SELECT edit_type, target_metric, before_value, after_value
|
|
127
|
-
FROM brain_edits WHERE analysis_run_id = ?
|
|
128
|
-
""",
|
|
129
|
-
(target_run_id,),
|
|
130
|
-
).fetchall()
|
|
131
|
-
version_rows = conn.execute(
|
|
132
|
-
"""
|
|
133
|
-
SELECT COUNT(*) AS c, MIN(version) AS min_v, MAX(version) AS max_v
|
|
134
|
-
FROM timeline_versions WHERE analysis_run_id = ?
|
|
135
|
-
""",
|
|
136
|
-
(target_run_id,),
|
|
137
|
-
).fetchone()
|
|
138
|
-
|
|
139
|
-
summary = _summarise_run(list(edits), version_rows)
|
|
140
|
-
ended_at = _now_iso()
|
|
141
|
-
with timeline_brain_db.transaction(project_root) as txn:
|
|
142
|
-
txn.execute(
|
|
143
|
-
"UPDATE analysis_runs SET ended_at = ?, summary_json = ? WHERE id = ?",
|
|
144
|
-
(ended_at, json.dumps(summary), target_run_id),
|
|
145
|
-
)
|
|
146
|
-
|
|
147
|
-
return {
|
|
148
|
-
"success": True,
|
|
149
|
-
"analysis_run_id": target_run_id,
|
|
150
|
-
"ended_at": ended_at,
|
|
151
|
-
"summary": summary,
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
def current_run_id() -> Optional[str]:
|
|
156
|
-
"""Read the active process-level run ID. None if no run is open."""
|
|
157
|
-
with _LOCK:
|
|
158
|
-
return _CURRENT_RUN["id"]
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
# ── B3 — Auto-run lifecycle ──────────────────────────────────────────────────
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
def ensure_auto_run_for_destructive(
|
|
165
|
-
*,
|
|
166
|
-
project_root: str,
|
|
167
|
-
idle_timeout_seconds: Optional[float] = None,
|
|
168
|
-
) -> str:
|
|
169
|
-
"""Return the analysis_run_id to use for a destructive op.
|
|
170
|
-
|
|
171
|
-
Behavior:
|
|
172
|
-
- If a run is already active and within the idle timeout: reuse it, bump idle timer.
|
|
173
|
-
- If a run is active but idle timer expired: end_run it, open a fresh auto-run.
|
|
174
|
-
- If no run is active: open a fresh auto-run with initiator="auto".
|
|
175
|
-
|
|
176
|
-
The caller (destructive_hook) plumbs the returned run_id through the
|
|
177
|
-
rest of its bookkeeping just as it would an explicit begin_run id.
|
|
178
|
-
"""
|
|
179
|
-
timeout = float(idle_timeout_seconds if idle_timeout_seconds is not None else _DEFAULT_AUTO_RUN_IDLE_TIMEOUT_S)
|
|
180
|
-
now = time.time()
|
|
181
|
-
with _LOCK:
|
|
182
|
-
active = _CURRENT_RUN["id"]
|
|
183
|
-
last = _LAST_DESTRUCTIVE_AT["epoch"]
|
|
184
|
-
if active and last and (now - last) > timeout:
|
|
185
|
-
# idle timeout — auto-close before opening fresh
|
|
186
|
-
stale_id = active
|
|
187
|
-
_CURRENT_RUN["id"] = None
|
|
188
|
-
_CURRENT_RUN["initiator"] = None
|
|
189
|
-
_CURRENT_RUN["label"] = None
|
|
190
|
-
else:
|
|
191
|
-
stale_id = None
|
|
192
|
-
|
|
193
|
-
if stale_id:
|
|
194
|
-
try:
|
|
195
|
-
end_run(project_root=project_root, analysis_run_id=stale_id)
|
|
196
|
-
except Exception as exc: # never block the destructive call on close failure
|
|
197
|
-
logger.warning("auto end_run for %s failed: %s", stale_id, exc)
|
|
198
|
-
|
|
199
|
-
with _LOCK:
|
|
200
|
-
if _CURRENT_RUN["id"]:
|
|
201
|
-
_LAST_DESTRUCTIVE_AT["epoch"] = now
|
|
202
|
-
return str(_CURRENT_RUN["id"])
|
|
203
|
-
|
|
204
|
-
# Open a fresh auto-run.
|
|
205
|
-
result = begin_run(project_root=project_root, label=f"auto-{_now_iso()}", initiator="auto")
|
|
206
|
-
with _LOCK:
|
|
207
|
-
_LAST_DESTRUCTIVE_AT["epoch"] = now
|
|
208
|
-
return str(result["analysis_run_id"])
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
def bump_idle_timer() -> None:
|
|
212
|
-
"""Called by destructive_hook on every wrap entry within an active run."""
|
|
213
|
-
with _LOCK:
|
|
214
|
-
_LAST_DESTRUCTIVE_AT["epoch"] = time.time()
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
def current_run_initiator() -> Optional[str]:
|
|
218
|
-
with _LOCK:
|
|
219
|
-
return _CURRENT_RUN["initiator"]
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
def get_run(project_root: str, analysis_run_id: str) -> Optional[Dict[str, Any]]:
|
|
223
|
-
conn = timeline_brain_db.connect(project_root)
|
|
224
|
-
row = conn.execute(
|
|
225
|
-
"SELECT id, label, initiator, started_at, ended_at, summary_json FROM analysis_runs WHERE id = ?",
|
|
226
|
-
(analysis_run_id,),
|
|
227
|
-
).fetchone()
|
|
228
|
-
if row is None:
|
|
229
|
-
return None
|
|
230
|
-
out = dict(row)
|
|
231
|
-
raw = out.pop("summary_json")
|
|
232
|
-
out["summary"] = json.loads(raw) if raw else None
|
|
233
|
-
return out
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
def list_runs(project_root: str, *, limit: int = 50) -> List[Dict[str, Any]]:
|
|
237
|
-
# SQLite treats a negative LIMIT as "no limit"; clamp (EX8).
|
|
238
|
-
try:
|
|
239
|
-
limit = max(1, min(1000, int(limit)))
|
|
240
|
-
except (TypeError, ValueError):
|
|
241
|
-
limit = 50
|
|
242
|
-
conn = timeline_brain_db.connect(project_root)
|
|
243
|
-
rows = conn.execute(
|
|
244
|
-
"""
|
|
245
|
-
SELECT id, label, initiator, started_at, ended_at, summary_json
|
|
246
|
-
FROM analysis_runs
|
|
247
|
-
ORDER BY started_at DESC
|
|
248
|
-
LIMIT ?
|
|
249
|
-
""",
|
|
250
|
-
(int(limit),),
|
|
251
|
-
).fetchall()
|
|
252
|
-
out: List[Dict[str, Any]] = []
|
|
253
|
-
for r in rows:
|
|
254
|
-
d = dict(r)
|
|
255
|
-
raw = d.pop("summary_json")
|
|
256
|
-
d["summary"] = json.loads(raw) if raw else None
|
|
257
|
-
out.append(d)
|
|
258
|
-
return out
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
# ── Test hooks ───────────────────────────────────────────────────────────────
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
def _reset_for_test() -> None:
|
|
265
|
-
"""Tests only: clear the process-level current run."""
|
|
266
|
-
with _LOCK:
|
|
267
|
-
_CURRENT_RUN["id"] = None
|
|
268
|
-
_CURRENT_RUN["initiator"] = None
|
|
269
|
-
_CURRENT_RUN["label"] = None
|
|
270
|
-
_LAST_DESTRUCTIVE_AT["epoch"] = 0.0
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
# ── Helpers ──────────────────────────────────────────────────────────────────
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
def _summarise_run(edits: List[Any], version_row: Any) -> Dict[str, Any]:
|
|
277
|
-
"""Aggregate brain_edits into a per-metric rollup."""
|
|
278
|
-
per_metric: Dict[str, Dict[str, Any]] = {}
|
|
279
|
-
for edit in edits:
|
|
280
|
-
metric = edit["target_metric"] if isinstance(edit, dict) or hasattr(edit, "__getitem__") else None
|
|
281
|
-
try:
|
|
282
|
-
metric = edit["target_metric"]
|
|
283
|
-
before = edit["before_value"]
|
|
284
|
-
after = edit["after_value"]
|
|
285
|
-
except (KeyError, IndexError, TypeError):
|
|
286
|
-
continue
|
|
287
|
-
if not metric:
|
|
288
|
-
continue
|
|
289
|
-
bucket = per_metric.setdefault(metric, {"edit_count": 0, "first_before": None, "last_after": None, "total_delta": 0.0})
|
|
290
|
-
bucket["edit_count"] += 1
|
|
291
|
-
if before is not None and bucket["first_before"] is None:
|
|
292
|
-
bucket["first_before"] = float(before)
|
|
293
|
-
if after is not None:
|
|
294
|
-
bucket["last_after"] = float(after)
|
|
295
|
-
if before is not None and after is not None:
|
|
296
|
-
try:
|
|
297
|
-
bucket["total_delta"] = round(bucket["total_delta"] + (float(after) - float(before)), 6)
|
|
298
|
-
except (TypeError, ValueError):
|
|
299
|
-
pass
|
|
300
|
-
|
|
301
|
-
return {
|
|
302
|
-
"edit_count": len(edits),
|
|
303
|
-
"version_count": int(version_row["c"]) if version_row and version_row["c"] is not None else 0,
|
|
304
|
-
"first_version": (int(version_row["min_v"]) if version_row and version_row["min_v"] is not None else None),
|
|
305
|
-
"last_version": (int(version_row["max_v"]) if version_row and version_row["max_v"] is not None else None),
|
|
306
|
-
"per_metric": per_metric,
|
|
307
|
-
}
|