attocode-code-intel 0.1.0__py3-none-any.whl
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.
- attocode_code_intel-0.1.0.dist-info/METADATA +221 -0
- attocode_code_intel-0.1.0.dist-info/RECORD +345 -0
- attocode_code_intel-0.1.0.dist-info/WHEEL +4 -0
- attocode_code_intel-0.1.0.dist-info/entry_points.txt +2 -0
- attocode_code_intel-0.1.0.dist-info/licenses/LICENSE +21 -0
- attocode_intel/GUIDELINES.md +432 -0
- attocode_intel/__init__.py +52 -0
- attocode_intel/_internal/__init__.py +1 -0
- attocode_intel/_internal/errors/__init__.py +126 -0
- attocode_intel/_internal/integrations/__init__.py +1 -0
- attocode_intel/_internal/integrations/context/__init__.py +1 -0
- attocode_intel/_internal/integrations/context/architecture_drift.py +354 -0
- attocode_intel/_internal/integrations/context/ast_chunker.py +202 -0
- attocode_intel/_internal/integrations/context/ast_service.py +1483 -0
- attocode_intel/_internal/integrations/context/blob_oid.py +423 -0
- attocode_intel/_internal/integrations/context/cache_manifest.py +221 -0
- attocode_intel/_internal/integrations/context/cas.py +466 -0
- attocode_intel/_internal/integrations/context/code_analyzer.py +528 -0
- attocode_intel/_internal/integrations/context/codebase_ast.py +1461 -0
- attocode_intel/_internal/integrations/context/codebase_context.py +1736 -0
- attocode_intel/_internal/integrations/context/cross_mode.py +263 -0
- attocode_intel/_internal/integrations/context/cross_references.py +616 -0
- attocode_intel/_internal/integrations/context/embedding_rotation.py +597 -0
- attocode_intel/_internal/integrations/context/embeddings.py +282 -0
- attocode_intel/_internal/integrations/context/frecency.py +427 -0
- attocode_intel/_internal/integrations/context/fuzzy.py +320 -0
- attocode_intel/_internal/integrations/context/hierarchical_explorer.py +331 -0
- attocode_intel/_internal/integrations/context/hydration.py +90 -0
- attocode_intel/_internal/integrations/context/index_repair.py +87 -0
- attocode_intel/_internal/integrations/context/index_store.py +586 -0
- attocode_intel/_internal/integrations/context/memory_store.py +602 -0
- attocode_intel/_internal/integrations/context/module_resolution.py +52 -0
- attocode_intel/_internal/integrations/context/query_constraints.py +361 -0
- attocode_intel/_internal/integrations/context/query_history.py +417 -0
- attocode_intel/_internal/integrations/context/reranker.py +351 -0
- attocode_intel/_internal/integrations/context/semantic_search.py +2931 -0
- attocode_intel/_internal/integrations/context/syntax_evidence.py +94 -0
- attocode_intel/_internal/integrations/context/systemone_ranker.py +245 -0
- attocode_intel/_internal/integrations/context/temporal_coupling.py +411 -0
- attocode_intel/_internal/integrations/context/trigram_index.py +820 -0
- attocode_intel/_internal/integrations/context/trigram_regex.py +171 -0
- attocode_intel/_internal/integrations/context/ts_parser.py +2199 -0
- attocode_intel/_internal/integrations/context/vector_store.py +795 -0
- attocode_intel/_internal/integrations/feature_flags/__init__.py +357 -0
- attocode_intel/_internal/integrations/lsp/__init__.py +1 -0
- attocode_intel/_internal/integrations/lsp/client.py +1140 -0
- attocode_intel/_internal/integrations/mcp/__init__.py +1 -0
- attocode_intel/_internal/integrations/mcp/client.py +253 -0
- attocode_intel/_internal/integrations/security/__init__.py +1 -0
- attocode_intel/_internal/integrations/security/custom_rules.py +176 -0
- attocode_intel/_internal/integrations/security/dataflow.py +522 -0
- attocode_intel/_internal/integrations/security/dependency_audit.py +303 -0
- attocode_intel/_internal/integrations/security/matcher.py +44 -0
- attocode_intel/_internal/integrations/security/patterns.py +724 -0
- attocode_intel/_internal/integrations/security/scanner.py +351 -0
- attocode_intel/_internal/integrations/utilities/__init__.py +1 -0
- attocode_intel/_internal/integrations/utilities/ignore.py +64 -0
- attocode_intel/_internal/integrations/utilities/token_estimate.py +51 -0
- attocode_intel/_internal/tricks/__init__.py +1 -0
- attocode_intel/_internal/tricks/recursive_context.py +357 -0
- attocode_intel/_internal/types/__init__.py +1 -0
- attocode_intel/_internal/types/events.py +289 -0
- attocode_intel/_internal/types/severity.py +15 -0
- attocode_intel/_shared.py +341 -0
- attocode_intel/analysis_coverage.py +56 -0
- attocode_intel/api/__init__.py +1 -0
- attocode_intel/api/access.py +32 -0
- attocode_intel/api/app.py +247 -0
- attocode_intel/api/auth/__init__.py +128 -0
- attocode_intel/api/auth/api_keys.py +61 -0
- attocode_intel/api/auth/context.py +34 -0
- attocode_intel/api/auth/jwt.py +66 -0
- attocode_intel/api/auth/oauth.py +146 -0
- attocode_intel/api/auth/passwords.py +15 -0
- attocode_intel/api/deps.py +351 -0
- attocode_intel/api/knowledge_bridge.py +13 -0
- attocode_intel/api/mcp_transport.py +51 -0
- attocode_intel/api/middleware.py +411 -0
- attocode_intel/api/models.py +698 -0
- attocode_intel/api/providers/__init__.py +1 -0
- attocode_intel/api/providers/db_provider.py +1106 -0
- attocode_intel/api/providers/local_provider.py +476 -0
- attocode_intel/api/providers/remote_provider.py +740 -0
- attocode_intel/api/repository_source.py +21 -0
- attocode_intel/api/routes/__init__.py +1 -0
- attocode_intel/api/routes/_pin_helper.py +158 -0
- attocode_intel/api/routes/activity.py +148 -0
- attocode_intel/api/routes/adr.py +102 -0
- attocode_intel/api/routes/analysis.py +515 -0
- attocode_intel/api/routes/api_keys.py +170 -0
- attocode_intel/api/routes/auth.py +428 -0
- attocode_intel/api/routes/branches.py +262 -0
- attocode_intel/api/routes/cross_repo_search.py +198 -0
- attocode_intel/api/routes/embeddings.py +386 -0
- attocode_intel/api/routes/files.py +132 -0
- attocode_intel/api/routes/files_v2.py +388 -0
- attocode_intel/api/routes/gc.py +322 -0
- attocode_intel/api/routes/git_v2.py +433 -0
- attocode_intel/api/routes/graph.py +174 -0
- attocode_intel/api/routes/graph_viz.py +160 -0
- attocode_intel/api/routes/health.py +62 -0
- attocode_intel/api/routes/history.py +175 -0
- attocode_intel/api/routes/jobs.py +84 -0
- attocode_intel/api/routes/learning.py +205 -0
- attocode_intel/api/routes/lsp.py +272 -0
- attocode_intel/api/routes/notify.py +623 -0
- attocode_intel/api/routes/operations.py +27 -0
- attocode_intel/api/routes/orgs.py +924 -0
- attocode_intel/api/routes/preferences.py +100 -0
- attocode_intel/api/routes/presence.py +42 -0
- attocode_intel/api/routes/projects.py +116 -0
- attocode_intel/api/routes/repos.py +47 -0
- attocode_intel/api/routes/search.py +180 -0
- attocode_intel/api/routes/snapshots.py +614 -0
- attocode_intel/api/routes/webhooks.py +313 -0
- attocode_intel/api/routes/websocket.py +116 -0
- attocode_intel/api/static/graph.html +239 -0
- attocode_intel/api/utils.py +96 -0
- attocode_intel/artifacts/__init__.py +45 -0
- attocode_intel/artifacts/hashing.py +230 -0
- attocode_intel/artifacts/provenance.py +190 -0
- attocode_intel/artifacts/retrieval_pin.py +159 -0
- attocode_intel/audit.py +59 -0
- attocode_intel/bug_finder.py +206 -0
- attocode_intel/bundle.py +80 -0
- attocode_intel/catalog.py +242 -0
- attocode_intel/change_review.py +75 -0
- attocode_intel/cli.py +3062 -0
- attocode_intel/community.py +63 -0
- attocode_intel/confidence/__init__.py +144 -0
- attocode_intel/confidence/jev.py +234 -0
- attocode_intel/confidence/llm.py +330 -0
- attocode_intel/confidence/redact.py +44 -0
- attocode_intel/confidence/settings.py +74 -0
- attocode_intel/config.py +256 -0
- attocode_intel/crypto.py +31 -0
- attocode_intel/db/__init__.py +7 -0
- attocode_intel/db/base.py +33 -0
- attocode_intel/db/engine.py +61 -0
- attocode_intel/db/models.py +529 -0
- attocode_intel/entrypoint.py +185 -0
- attocode_intel/focused_evidence.py +130 -0
- attocode_intel/freshness.py +154 -0
- attocode_intel/gateway.py +734 -0
- attocode_intel/git/__init__.py +7 -0
- attocode_intel/git/credentials.py +75 -0
- attocode_intel/git/manager.py +493 -0
- attocode_intel/git/models.py +96 -0
- attocode_intel/git/storage.py +98 -0
- attocode_intel/graph_query_parser.py +761 -0
- attocode_intel/helpers.py +712 -0
- attocode_intel/indexing/__init__.py +29 -0
- attocode_intel/indexing/debouncer.py +136 -0
- attocode_intel/indexing/delta_indexer.py +151 -0
- attocode_intel/indexing/full_indexer.py +323 -0
- attocode_intel/indexing/incremental.py +240 -0
- attocode_intel/indexing/parser.py +403 -0
- attocode_intel/indexing/summarizer.py +264 -0
- attocode_intel/installer.py +1896 -0
- attocode_intel/knowledge.py +269 -0
- attocode_intel/local_knowledge.py +77 -0
- attocode_intel/migrations/alembic.ini +36 -0
- attocode_intel/migrations/env.py +71 -0
- attocode_intel/migrations/script.py.mako +27 -0
- attocode_intel/migrations/versions/001_initial_schema.py +219 -0
- attocode_intel/migrations/versions/002_branch_version_and_embeddings.py +61 -0
- attocode_intel/migrations/versions/003_embedding_uniqueness_and_cascade.py +51 -0
- attocode_intel/migrations/versions/004_audit_events.py +38 -0
- attocode_intel/migrations/versions/005_user_preferences.py +30 -0
- attocode_intel/migrations/versions/006_google_oauth.py +27 -0
- attocode_intel/migrations/versions/007_pgvector_embeddings.py +28 -0
- attocode_intel/migrations/versions/008_symbol_references.py +37 -0
- attocode_intel/migrations/versions/009_webhook_secret_encryption.py +25 -0
- attocode_intel/migrations/versions/010_add_commits_table.py +40 -0
- attocode_intel/migrations/versions/011_commit_changed_files.py +25 -0
- attocode_intel/migrations/versions/012_branch_merged_at.py +25 -0
- attocode_intel/migrations/versions/013_revoked_tokens.py +32 -0
- attocode_intel/migrations/versions/014_blame_hunks.py +40 -0
- attocode_intel/migrations/versions/015_commit_file_stats.py +40 -0
- attocode_intel/migrations/versions/016_embedding_provenance_columns.py +179 -0
- attocode_intel/migrations/versions/017_provenance_table.py +102 -0
- attocode_intel/migrations/versions/018_repo_snapshots.py +178 -0
- attocode_intel/migrations/versions/019_symref_caller.py +42 -0
- attocode_intel/migrations/versions/020_shared_knowledge.py +29 -0
- attocode_intel/onboarding.py +258 -0
- attocode_intel/output.py +178 -0
- attocode_intel/precision.py +133 -0
- attocode_intel/presence.py +160 -0
- attocode_intel/probe.py +110 -0
- attocode_intel/project_dir.py +97 -0
- attocode_intel/pubsub.py +113 -0
- attocode_intel/query_ranking.py +242 -0
- attocode_intel/readiness.py +972 -0
- attocode_intel/redis.py +51 -0
- attocode_intel/reference_pages.py +60 -0
- attocode_intel/remote.py +131 -0
- attocode_intel/repo_ranker.py +246 -0
- attocode_intel/request_context.py +82 -0
- attocode_intel/rules/__init__.py +28 -0
- attocode_intel/rules/ci.py +320 -0
- attocode_intel/rules/combinators.py +293 -0
- attocode_intel/rules/enricher.py +127 -0
- attocode_intel/rules/evolution.py +452 -0
- attocode_intel/rules/executor.py +531 -0
- attocode_intel/rules/filters/__init__.py +5 -0
- attocode_intel/rules/filters/pipeline.py +151 -0
- attocode_intel/rules/formatter.py +198 -0
- attocode_intel/rules/hygiene.py +242 -0
- attocode_intel/rules/importers/__init__.py +1 -0
- attocode_intel/rules/importers/semgrep.py +382 -0
- attocode_intel/rules/loader.py +292 -0
- attocode_intel/rules/marketplace.py +375 -0
- attocode_intel/rules/metavar.py +181 -0
- attocode_intel/rules/model.py +317 -0
- attocode_intel/rules/packs/__init__.py +1 -0
- attocode_intel/rules/packs/community/_license_templates/Apache-2.0.txt +176 -0
- attocode_intel/rules/packs/community/_license_templates/MIT.txt +21 -0
- attocode_intel/rules/packs/community/bandit-python/LICENSE +176 -0
- attocode_intel/rules/packs/community/bandit-python/NOTICE +13 -0
- attocode_intel/rules/packs/community/bandit-python/PORTING.md +23 -0
- attocode_intel/rules/packs/community/bandit-python/manifest.yaml +14 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B105-hardcoded-password.yaml +23 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B303-weak-md5.yaml +21 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B304-weak-des.yaml +20 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B307-use-of-eval.yaml +22 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B324-weak-sha1.yaml +21 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B501-no-cert-validation.yaml +23 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B602-shell-true.yaml +22 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B608-sqli.yaml +22 -0
- attocode_intel/rules/packs/community/eslint-typescript/LICENSE +21 -0
- attocode_intel/rules/packs/community/eslint-typescript/NOTICE +13 -0
- attocode_intel/rules/packs/community/eslint-typescript/PORTING.md +23 -0
- attocode_intel/rules/packs/community/eslint-typescript/manifest.yaml +14 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/eqeqeq.yaml +20 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-eval.yaml +22 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-implied-eval.yaml +20 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-new-func.yaml +21 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-throw-literal.yaml +19 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-var.yaml +20 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-with.yaml +18 -0
- attocode_intel/rules/packs/community/gosec-go/LICENSE +176 -0
- attocode_intel/rules/packs/community/gosec-go/NOTICE +13 -0
- attocode_intel/rules/packs/community/gosec-go/PORTING.md +23 -0
- attocode_intel/rules/packs/community/gosec-go/manifest.yaml +14 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G101-hardcoded-credentials.yaml +22 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G102-bind-all-interfaces.yaml +21 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G103-unsafe-block.yaml +21 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G201-sql-format.yaml +21 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G304-file-inclusion.yaml +23 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G401-weak-cipher.yaml +20 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G402-tls-min-version.yaml +20 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G501-md5-import.yaml +21 -0
- attocode_intel/rules/packs/examples/cpp/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/cpp/rules/security.yaml +90 -0
- attocode_intel/rules/packs/examples/cpp/rules/structural.yaml +42 -0
- attocode_intel/rules/packs/examples/csharp/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/csharp/rules/security.yaml +69 -0
- attocode_intel/rules/packs/examples/csharp/rules/structural.yaml +42 -0
- attocode_intel/rules/packs/examples/go/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/go/rules/performance.yaml +136 -0
- attocode_intel/rules/packs/examples/go/rules/security.yaml +48 -0
- attocode_intel/rules/packs/examples/go/rules/structural.yaml +58 -0
- attocode_intel/rules/packs/examples/go/taint/sanitizers.yaml +24 -0
- attocode_intel/rules/packs/examples/go/taint/sinks.yaml +51 -0
- attocode_intel/rules/packs/examples/go/taint/sources.yaml +26 -0
- attocode_intel/rules/packs/examples/java/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/java/rules/correctness.yaml +55 -0
- attocode_intel/rules/packs/examples/java/rules/structural.yaml +48 -0
- attocode_intel/rules/packs/examples/java/taint/sinks.yaml +37 -0
- attocode_intel/rules/packs/examples/java/taint/sources.yaml +21 -0
- attocode_intel/rules/packs/examples/kotlin/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/kotlin/rules/correctness.yaml +50 -0
- attocode_intel/rules/packs/examples/kotlin/rules/structural.yaml +38 -0
- attocode_intel/rules/packs/examples/php/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/php/rules/security.yaml +66 -0
- attocode_intel/rules/packs/examples/php/rules/structural.yaml +41 -0
- attocode_intel/rules/packs/examples/python/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/python/rules/performance.yaml +90 -0
- attocode_intel/rules/packs/examples/python/rules/structural.yaml +55 -0
- attocode_intel/rules/packs/examples/ruby/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/ruby/rules/security.yaml +73 -0
- attocode_intel/rules/packs/examples/ruby/rules/structural.yaml +41 -0
- attocode_intel/rules/packs/examples/rust/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/rust/rules/correctness.yaml +51 -0
- attocode_intel/rules/packs/examples/rust/rules/structural.yaml +49 -0
- attocode_intel/rules/packs/examples/typescript/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/typescript/rules/performance.yaml +70 -0
- attocode_intel/rules/packs/examples/typescript/rules/structural.yaml +48 -0
- attocode_intel/rules/packs/pack_loader.py +244 -0
- attocode_intel/rules/plugins/__init__.py +1 -0
- attocode_intel/rules/plugins/plugin_loader.py +132 -0
- attocode_intel/rules/profiling.py +332 -0
- attocode_intel/rules/registry.py +213 -0
- attocode_intel/rules/sarif.py +187 -0
- attocode_intel/rules/synthesis.py +420 -0
- attocode_intel/rules/testing.py +326 -0
- attocode_intel/server.py +734 -0
- attocode_intel/service.py +3416 -0
- attocode_intel/sharing.py +57 -0
- attocode_intel/storage/__init__.py +6 -0
- attocode_intel/storage/branch_overlay.py +352 -0
- attocode_intel/storage/content_store.py +220 -0
- attocode_intel/storage/dependency_store.py +143 -0
- attocode_intel/storage/diff_engine.py +187 -0
- attocode_intel/storage/embedding_store.py +594 -0
- attocode_intel/storage/provenance_store.py +137 -0
- attocode_intel/storage/security_scanner_db.py +164 -0
- attocode_intel/storage/symbol_store.py +160 -0
- attocode_intel/structural_evidence.py +144 -0
- attocode_intel/symbol_inspection.py +141 -0
- attocode_intel/symbol_links.py +167 -0
- attocode_intel/telemetry.py +42 -0
- attocode_intel/test_ranking.py +73 -0
- attocode_intel/testing/__init__.py +43 -0
- attocode_intel/testing/fixtures.py +122 -0
- attocode_intel/testing/helpers.py +75 -0
- attocode_intel/testing/mocks.py +99 -0
- attocode_intel/tools/__init__.py +2 -0
- attocode_intel/tools/adr_tools.py +628 -0
- attocode_intel/tools/analysis_tools.py +382 -0
- attocode_intel/tools/composite_tools.py +695 -0
- attocode_intel/tools/cross_mode_tools.py +173 -0
- attocode_intel/tools/dead_code_tools.py +582 -0
- attocode_intel/tools/distill_tools.py +353 -0
- attocode_intel/tools/frecency_tools.py +220 -0
- attocode_intel/tools/fuzzy_tools.py +255 -0
- attocode_intel/tools/history_tools.py +486 -0
- attocode_intel/tools/learning_tools.py +222 -0
- attocode_intel/tools/lsp_tools.py +218 -0
- attocode_intel/tools/maintenance_tools.py +1662 -0
- attocode_intel/tools/navigation_tools.py +220 -0
- attocode_intel/tools/overlay_tools.py +540 -0
- attocode_intel/tools/pin_store.py +432 -0
- attocode_intel/tools/pin_tools.py +266 -0
- attocode_intel/tools/query_constraints_tools.py +262 -0
- attocode_intel/tools/query_history_tools.py +158 -0
- attocode_intel/tools/readiness_tools.py +44 -0
- attocode_intel/tools/rule_tools.py +992 -0
- attocode_intel/tools/search_tools.py +770 -0
- attocode_intel/tools/snapshot_tools.py +624 -0
- attocode_intel/workers/__init__.py +1 -0
- attocode_intel/workers/job_utils.py +111 -0
- attocode_intel/workers/jobs.py +573 -0
- attocode_intel/workers/run.py +30 -0
- attocode_intel/workers/settings.py +61 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
"""Feature flag registry — gate capabilities via environment/config.
|
|
2
|
+
|
|
3
|
+
Unlike CC's Bun-based feature('NAME') with dead-code elimination,
|
|
4
|
+
this uses simple env-var lookup with optional override config.
|
|
5
|
+
Each flag can also carry a description and deprecation notice.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import re
|
|
12
|
+
from dataclasses import dataclass, field
|
|
13
|
+
from enum import StrEnum
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class FlagKind(StrEnum):
|
|
18
|
+
"""Kind of flag — controls how the flag value is interpreted."""
|
|
19
|
+
|
|
20
|
+
BOOLEAN = "boolean" # true/false
|
|
21
|
+
STRING = "string" # any string value
|
|
22
|
+
NUMBER = "number" # numeric value
|
|
23
|
+
ENUM = "enum" # one of a fixed set of values
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class FeatureFlag:
|
|
28
|
+
"""A single feature flag definition."""
|
|
29
|
+
|
|
30
|
+
name: str
|
|
31
|
+
kind: FlagKind
|
|
32
|
+
description: str
|
|
33
|
+
default: Any = False
|
|
34
|
+
env_var: str | None = None # Override env var name (defaults to ATTOCODE_FLAG_<NAME>)
|
|
35
|
+
valid_values: list[str] = field(default_factory=list) # For ENUM kind
|
|
36
|
+
deprecated: bool = False
|
|
37
|
+
deprecation_message: str = ""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# -----------------------------------------------------------------------------
|
|
41
|
+
# Flag definitions
|
|
42
|
+
# -----------------------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
ALL_FLAGS: dict[str, FeatureFlag] = {}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _register(flag: FeatureFlag) -> None:
|
|
48
|
+
ALL_FLAGS[flag.name] = flag
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
_register(FeatureFlag(
|
|
52
|
+
name="TOOL_DEFERRED_SEARCH",
|
|
53
|
+
kind=FlagKind.BOOLEAN,
|
|
54
|
+
description="Mark expensive tools (LSP, semantic search) as deferred. "
|
|
55
|
+
"The model does a ToolSearch roundtrip before calling them.",
|
|
56
|
+
default=False,
|
|
57
|
+
))
|
|
58
|
+
_register(FeatureFlag(
|
|
59
|
+
name="COORDINATOR_MODE",
|
|
60
|
+
kind=FlagKind.BOOLEAN,
|
|
61
|
+
description="Enable the orchestrator as a first-class coordinator "
|
|
62
|
+
"with explicit phase management and worker synthesis.",
|
|
63
|
+
default=False,
|
|
64
|
+
))
|
|
65
|
+
_register(FeatureFlag(
|
|
66
|
+
name="CONTEXT_COLLAPSE",
|
|
67
|
+
kind=FlagKind.BOOLEAN,
|
|
68
|
+
description="Collapse redundant tool results that repeat the same information.",
|
|
69
|
+
default=False,
|
|
70
|
+
))
|
|
71
|
+
_register(FeatureFlag(
|
|
72
|
+
name="REACTIVE_COMPACT",
|
|
73
|
+
kind=FlagKind.BOOLEAN,
|
|
74
|
+
description="Trigger compaction reactively based on model signals "
|
|
75
|
+
"rather than only on threshold.",
|
|
76
|
+
default=False,
|
|
77
|
+
))
|
|
78
|
+
_register(FeatureFlag(
|
|
79
|
+
name="BG_SESSIONS",
|
|
80
|
+
kind=FlagKind.BOOLEAN,
|
|
81
|
+
description="Enable background task sessions with foreground/background "
|
|
82
|
+
"switching and isolated transcript.",
|
|
83
|
+
default=False,
|
|
84
|
+
))
|
|
85
|
+
_register(FeatureFlag(
|
|
86
|
+
name="SKILL_IMPROVEMENT",
|
|
87
|
+
kind=FlagKind.BOOLEAN,
|
|
88
|
+
description="Enable skill auto-improvement hooks that detect "
|
|
89
|
+
"and fix underperforming skills.",
|
|
90
|
+
default=False,
|
|
91
|
+
))
|
|
92
|
+
_register(FeatureFlag(
|
|
93
|
+
name="EXPERIMENTAL_SKILL_SEARCH",
|
|
94
|
+
kind=FlagKind.BOOLEAN,
|
|
95
|
+
description="Use semantic search to find relevant skills dynamically.",
|
|
96
|
+
default=False,
|
|
97
|
+
))
|
|
98
|
+
_register(FeatureFlag(
|
|
99
|
+
name="CALL_HIERARCHY",
|
|
100
|
+
kind=FlagKind.BOOLEAN,
|
|
101
|
+
description="Enable incoming/outgoing call hierarchy LSP tools.",
|
|
102
|
+
default=True,
|
|
103
|
+
))
|
|
104
|
+
_register(FeatureFlag(
|
|
105
|
+
name="GITIGNORED_FILTER",
|
|
106
|
+
kind=FlagKind.BOOLEAN,
|
|
107
|
+
description="Filter LSP location results to exclude gitignored paths.",
|
|
108
|
+
default=True,
|
|
109
|
+
))
|
|
110
|
+
_register(FeatureFlag(
|
|
111
|
+
name="MCP_SSE_TRANSPORT",
|
|
112
|
+
kind=FlagKind.BOOLEAN,
|
|
113
|
+
description="Enable SSE (Server-Sent Events) MCP transport.",
|
|
114
|
+
default=False,
|
|
115
|
+
))
|
|
116
|
+
_register(FeatureFlag(
|
|
117
|
+
name="MCP_HTTP_TRANSPORT",
|
|
118
|
+
kind=FlagKind.BOOLEAN,
|
|
119
|
+
description="Enable StreamableHTTP MCP transport.",
|
|
120
|
+
default=False,
|
|
121
|
+
))
|
|
122
|
+
_register(FeatureFlag(
|
|
123
|
+
name="UNC_PATH_BLOCK",
|
|
124
|
+
kind=FlagKind.BOOLEAN,
|
|
125
|
+
description="Block UNC paths (\\\\server, //server) to prevent credential leaks.",
|
|
126
|
+
default=True,
|
|
127
|
+
))
|
|
128
|
+
_register(FeatureFlag(
|
|
129
|
+
name="LSP_PROTOCOL_TRACE",
|
|
130
|
+
kind=FlagKind.BOOLEAN,
|
|
131
|
+
description="Enable verbose LSP protocol tracing for debugging.",
|
|
132
|
+
default=False,
|
|
133
|
+
))
|
|
134
|
+
_register(FeatureFlag(
|
|
135
|
+
name="DIVERSE_SERIALIZATION",
|
|
136
|
+
kind=FlagKind.BOOLEAN,
|
|
137
|
+
description="Use diverse serialization formats for context compression.",
|
|
138
|
+
default=False,
|
|
139
|
+
))
|
|
140
|
+
_register(FeatureFlag(
|
|
141
|
+
name="FRESH_CONTEXT_THRESHOLD",
|
|
142
|
+
kind=FlagKind.NUMBER,
|
|
143
|
+
description="Token fraction (0-1) that triggers fresh context refresh. "
|
|
144
|
+
"Set via ATTOCODE_FLAG_FRESH_CONTEXT_THRESHOLD=0.5.",
|
|
145
|
+
default=0.6,
|
|
146
|
+
))
|
|
147
|
+
_register(FeatureFlag(
|
|
148
|
+
name="TOOL_RESULT_DISK_CACHE",
|
|
149
|
+
kind=FlagKind.BOOLEAN,
|
|
150
|
+
description="Persist large tool results to disk and reference them "
|
|
151
|
+
"instead of keeping full content in context.",
|
|
152
|
+
default=False,
|
|
153
|
+
))
|
|
154
|
+
_register(FeatureFlag(
|
|
155
|
+
name="RECITATION_MODE",
|
|
156
|
+
kind=FlagKind.ENUM,
|
|
157
|
+
description="How to inject goal recitation. Options: off, periodic, adaptive.",
|
|
158
|
+
default="periodic",
|
|
159
|
+
valid_values=["off", "periodic", "adaptive"],
|
|
160
|
+
))
|
|
161
|
+
_register(FeatureFlag(
|
|
162
|
+
name="HOOKS_TRACE",
|
|
163
|
+
kind=FlagKind.BOOLEAN,
|
|
164
|
+
description="Log all hook invocations for debugging.",
|
|
165
|
+
default=False,
|
|
166
|
+
))
|
|
167
|
+
_register(FeatureFlag(
|
|
168
|
+
name="FORK_SUBAGENTS",
|
|
169
|
+
kind=FlagKind.BOOLEAN,
|
|
170
|
+
description="Allow agents to fork themselves (share prompt cache, "
|
|
171
|
+
"new conversation thread). Requires provider support.",
|
|
172
|
+
default=False,
|
|
173
|
+
))
|
|
174
|
+
_register(FeatureFlag(
|
|
175
|
+
name="CONFIDENCE",
|
|
176
|
+
env_var="ATTOCODE_FLAG_CONFIDENCE",
|
|
177
|
+
kind=FlagKind.ENUM,
|
|
178
|
+
description="Where a finding's confidence comes from. off = the hardcoded "
|
|
179
|
+
"constants; jev = a calibrated probability; llm = the Haiku "
|
|
180
|
+
"false-positive classifier.",
|
|
181
|
+
default="off",
|
|
182
|
+
valid_values=["off", "jev", "llm"],
|
|
183
|
+
))
|
|
184
|
+
_register(FeatureFlag(
|
|
185
|
+
name="CONFIDENCE_MODE",
|
|
186
|
+
env_var="ATTOCODE_FLAG_CONFIDENCE_MODE",
|
|
187
|
+
kind=FlagKind.ENUM,
|
|
188
|
+
description="What to do with an estimate. shadow = log it beside the "
|
|
189
|
+
"constant and change nothing; live = use it.",
|
|
190
|
+
default="shadow",
|
|
191
|
+
valid_values=["shadow", "live"],
|
|
192
|
+
))
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
# -----------------------------------------------------------------------------
|
|
196
|
+
# Resolver
|
|
197
|
+
# -----------------------------------------------------------------------------
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class FlagResolver:
|
|
201
|
+
"""Resolve feature flag values from environment + overrides.
|
|
202
|
+
|
|
203
|
+
Supports three sources (in priority order):
|
|
204
|
+
1. Explicit overrides set via ``set_override``
|
|
205
|
+
2. Environment variables (ATTOCODE_FLAG_<NAME> or custom env_var)
|
|
206
|
+
3. Default value from the flag definition
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
def __init__(self) -> None:
|
|
210
|
+
self._overrides: dict[str, Any] = {}
|
|
211
|
+
self._resolved: dict[str, Any] = {} # Cache
|
|
212
|
+
|
|
213
|
+
def set_override(self, name: str, value: Any) -> None:
|
|
214
|
+
"""Force a flag to a specific value (for testing, CLI overrides)."""
|
|
215
|
+
self._overrides[name] = value
|
|
216
|
+
self._resolved.pop(name, None) # Invalidate cache
|
|
217
|
+
|
|
218
|
+
def clear_override(self, name: str) -> None:
|
|
219
|
+
"""Remove an override, reverting to env/default resolution."""
|
|
220
|
+
self._overrides.pop(name, None)
|
|
221
|
+
self._resolved.pop(name, None)
|
|
222
|
+
|
|
223
|
+
def resolve_with_default(self, name: str, default: Any) -> Any:
|
|
224
|
+
"""Resolve a request-specific default without caching it process-wide."""
|
|
225
|
+
flag = ALL_FLAGS[name]
|
|
226
|
+
env_var = flag.env_var or f"ATTOCODE_FLAG_{_to_env_name(name)}"
|
|
227
|
+
value = self._overrides.get(name, os.environ.get(env_var, default))
|
|
228
|
+
return self._coerce(flag, value)
|
|
229
|
+
|
|
230
|
+
def get(self, name: str) -> Any:
|
|
231
|
+
"""Resolve a flag value.
|
|
232
|
+
|
|
233
|
+
Returns the override, env-var, or default.
|
|
234
|
+
Raises KeyError if the flag name is unknown.
|
|
235
|
+
"""
|
|
236
|
+
if name in self._resolved:
|
|
237
|
+
return self._resolved[name]
|
|
238
|
+
|
|
239
|
+
flag = ALL_FLAGS.get(name)
|
|
240
|
+
if flag is None:
|
|
241
|
+
raise KeyError(f"Unknown feature flag: {name}")
|
|
242
|
+
|
|
243
|
+
# 1. Override
|
|
244
|
+
if name in self._overrides:
|
|
245
|
+
value = self._resolved[name] = self._coerce(flag, self._overrides[name])
|
|
246
|
+
return value
|
|
247
|
+
|
|
248
|
+
# 2. Environment
|
|
249
|
+
env_var = flag.env_var or f"ATTOCODE_FLAG_{_to_env_name(name)}"
|
|
250
|
+
raw = os.environ.get(env_var)
|
|
251
|
+
if raw is not None:
|
|
252
|
+
value = self._resolved[name] = self._coerce(flag, raw)
|
|
253
|
+
return value
|
|
254
|
+
|
|
255
|
+
# 3. Default
|
|
256
|
+
self._resolved[name] = flag.default
|
|
257
|
+
return flag.default
|
|
258
|
+
|
|
259
|
+
def _coerce(self, flag: FeatureFlag, raw: Any) -> Any:
|
|
260
|
+
"""Coerce a raw value to the flag's type."""
|
|
261
|
+
if flag.kind == FlagKind.BOOLEAN:
|
|
262
|
+
if isinstance(raw, bool):
|
|
263
|
+
return raw
|
|
264
|
+
if isinstance(raw, str):
|
|
265
|
+
return raw.lower() in ("1", "true", "yes", "on")
|
|
266
|
+
return bool(raw)
|
|
267
|
+
if flag.kind == FlagKind.NUMBER:
|
|
268
|
+
return float(raw) if flag.name != "FRESH_CONTEXT_THRESHOLD" else float(raw)
|
|
269
|
+
if flag.kind == FlagKind.ENUM:
|
|
270
|
+
if isinstance(raw, str) and raw in flag.valid_values:
|
|
271
|
+
return raw
|
|
272
|
+
return flag.default
|
|
273
|
+
# STRING
|
|
274
|
+
return str(raw)
|
|
275
|
+
|
|
276
|
+
def is_enabled(self, name: str) -> bool:
|
|
277
|
+
"""Boolean convenience — returns True if the flag is truthy."""
|
|
278
|
+
return bool(self.get(name))
|
|
279
|
+
|
|
280
|
+
def is_disabled(self, name: str) -> bool:
|
|
281
|
+
"""Boolean convenience — returns True if the flag is falsy."""
|
|
282
|
+
return not self.get(name)
|
|
283
|
+
|
|
284
|
+
def get_str(self, name: str, fallback: str = "") -> str:
|
|
285
|
+
"""String convenience — returns the flag as a string or fallback."""
|
|
286
|
+
val = self.get(name)
|
|
287
|
+
return str(val) if val is not None else fallback
|
|
288
|
+
|
|
289
|
+
def get_num(self, name: str, fallback: float = 0.0) -> float:
|
|
290
|
+
"""Numeric convenience — returns the flag as a float or fallback."""
|
|
291
|
+
try:
|
|
292
|
+
return float(self.get(name))
|
|
293
|
+
except (TypeError, ValueError):
|
|
294
|
+
return fallback
|
|
295
|
+
|
|
296
|
+
def list_all(self) -> dict[str, dict[str, Any]]:
|
|
297
|
+
"""Return all flags with their resolved values and metadata."""
|
|
298
|
+
return {
|
|
299
|
+
name: {
|
|
300
|
+
"value": self.get(name),
|
|
301
|
+
"kind": flag.kind.value,
|
|
302
|
+
"description": flag.description,
|
|
303
|
+
"default": flag.default,
|
|
304
|
+
"deprecated": flag.deprecated,
|
|
305
|
+
"has_override": name in self._overrides,
|
|
306
|
+
"env_var": flag.env_var or f"ATTOCODE_FLAG_{_to_env_name(name)}",
|
|
307
|
+
}
|
|
308
|
+
for name, flag in ALL_FLAGS.items()
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
def list_enabled(self) -> list[str]:
|
|
312
|
+
"""Return names of all currently-enabled flags."""
|
|
313
|
+
return [name for name in ALL_FLAGS if self.is_enabled(name)]
|
|
314
|
+
|
|
315
|
+
def dump_env_template(self) -> str:
|
|
316
|
+
"""Generate a shell snippet of all unset flags with their defaults."""
|
|
317
|
+
lines = ["# Attocode feature flags (auto-generated)", ""]
|
|
318
|
+
for name, flag in sorted(ALL_FLAGS.items()):
|
|
319
|
+
env_var = flag.env_var or f"ATTOCODE_FLAG_{_to_env_name(name)}"
|
|
320
|
+
default_str = "true" if flag.default is True else (
|
|
321
|
+
"false" if flag.default is False else str(flag.default)
|
|
322
|
+
)
|
|
323
|
+
lines.append(f"# {flag.description}")
|
|
324
|
+
if flag.kind == FlagKind.BOOLEAN:
|
|
325
|
+
lines.append(f"# export {env_var}=true # default: {default_str}")
|
|
326
|
+
elif flag.kind == FlagKind.ENUM:
|
|
327
|
+
opts = "|".join(flag.valid_values)
|
|
328
|
+
lines.append(f"# export {env_var}={flag.default} # options: {opts}")
|
|
329
|
+
else:
|
|
330
|
+
lines.append(f"# export {env_var}={flag.default}")
|
|
331
|
+
lines.append("")
|
|
332
|
+
return "\n".join(lines)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def _to_env_name(name: str) -> str:
|
|
336
|
+
"""Convert flag name to env-var format: SomeFlagName → SOME_FLAG_NAME."""
|
|
337
|
+
return re.sub(r"(?<!^)(?=[A-Z])", "_", name).upper()
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
# -----------------------------------------------------------------------------
|
|
341
|
+
# Global instance
|
|
342
|
+
# -----------------------------------------------------------------------------
|
|
343
|
+
|
|
344
|
+
# Create a module-level singleton so integrations can import and use flags
|
|
345
|
+
# without instantiating their own resolvers.
|
|
346
|
+
registry = FlagResolver()
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def feature(name: str) -> bool:
|
|
350
|
+
"""Boolean check: is a feature flag enabled?
|
|
351
|
+
|
|
352
|
+
Equivalent to CC's feature('NAME') but with env-var override support.
|
|
353
|
+
Example:
|
|
354
|
+
if feature("TOOL_DEFERRED_SEARCH"):
|
|
355
|
+
deferred_tools.append("lsp_definition")
|
|
356
|
+
"""
|
|
357
|
+
return registry.is_enabled(name)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Internal code intelligence support; not a public API."""
|