@blxzer/cursor-trellis 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -0
- package/README.md +45 -21
- package/dist/configurators/workflow.d.ts +1 -1
- package/dist/configurators/workflow.d.ts.map +1 -1
- package/dist/configurators/workflow.js +20 -9
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/migrations/manifests/0.1.3.json +9 -0
- package/dist/migrations/manifests/0.1.4.json +9 -0
- package/dist/templates/cursor/rules/retrieval-routing.mdc +9 -7
- package/dist/templates/markdown/agents.md +1 -1
- package/dist/templates/markdown/index.d.ts +1 -0
- package/dist/templates/markdown/index.d.ts.map +1 -1
- package/dist/templates/markdown/index.js +1 -0
- package/dist/templates/markdown/index.js.map +1 -1
- package/dist/templates/markdown/prompts/run-semantic-slice-12.md.txt +13 -29
- package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md.txt +0 -49
- package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +0 -85
- package/dist/templates/markdown/spec/guides/cursor-semantic-compliance.md.txt +7 -21
- package/dist/templates/markdown/spec/guides/cursor-subagent-policy.md.txt +6 -10
- package/dist/templates/markdown/spec/guides/retrieval-daily-guide.md.txt +17 -18
- package/dist/templates/shared-hooks/inject-retrieval-plan.py +42 -23
- package/dist/templates/shared-hooks/inject-subagent-context.py +6 -2
- package/dist/templates/shared-hooks/session-start.py +17 -9
- package/dist/templates/trellis/index.d.ts +8 -4
- package/dist/templates/trellis/index.d.ts.map +1 -1
- package/dist/templates/trellis/index.js +13 -7
- package/dist/templates/trellis/index.js.map +1 -1
- package/dist/templates/trellis/scripts/common/codebase_retrieval_router.py +80 -31
- package/dist/templates/trellis/scripts/common/config.py +1 -1
- package/dist/templates/trellis/scripts/common/cursor_retrieval_env.py +92 -0
- package/dist/templates/trellis/scripts/common/parent_orchestration.py +27 -15
- package/dist/templates/trellis/scripts/common/retrieval_adapter_metadata.py +100 -9
- package/dist/templates/trellis/scripts/common/retrieval_agent_instructions.py +76 -31
- package/dist/templates/trellis/scripts/common/retrieval_tool_classification.py +18 -3
- package/dist/templates/trellis/scripts/common/semantic_plan_gate.py +19 -0
- package/dist/templates/trellis/scripts/common/smart_search_evidence.py +5 -2
- package/dist/templates/trellis/scripts/common/smart_search_resolve.py +28 -3
- package/dist/templates/trellis/scripts/common/task_gates.py +372 -73
- package/dist/templates/trellis/scripts/common/task_map.py +29 -1
- package/dist/templates/trellis/scripts/cursor_retrieval_probe.py +396 -0
- package/dist/templates/trellis/scripts/cursor_retrieval_probe_prompt.md +300 -0
- package/dist/templates/trellis/scripts/retrieval_probe_matrix_template.json +126 -0
- package/dist/templates/trellis/workflow.md +9 -53
- package/dist/utils/codebase-retrieval-router.d.ts +5 -0
- package/dist/utils/codebase-retrieval-router.d.ts.map +1 -1
- package/dist/utils/codebase-retrieval-router.js +48 -28
- package/dist/utils/codebase-retrieval-router.js.map +1 -1
- package/dist/utils/cursor-retrieval-env.d.ts +28 -0
- package/dist/utils/cursor-retrieval-env.d.ts.map +1 -0
- package/dist/utils/cursor-retrieval-env.js +89 -0
- package/dist/utils/cursor-retrieval-env.js.map +1 -0
- package/dist/utils/project-capabilities.d.ts.map +1 -1
- package/dist/utils/project-capabilities.js +22 -15
- package/dist/utils/project-capabilities.js.map +1 -1
- package/dist/utils/retrieval-agent-instructions.d.ts.map +1 -1
- package/dist/utils/retrieval-agent-instructions.js +37 -21
- package/dist/utils/retrieval-agent-instructions.js.map +1 -1
- package/dist/utils/retrieval-tool-classification.d.ts +2 -0
- package/dist/utils/retrieval-tool-classification.d.ts.map +1 -1
- package/dist/utils/retrieval-tool-classification.js +10 -2
- package/dist/utils/retrieval-tool-classification.js.map +1 -1
- package/dist/utils/semantic-plan-gate.d.ts +8 -0
- package/dist/utils/semantic-plan-gate.d.ts.map +1 -0
- package/dist/utils/semantic-plan-gate.js +42 -0
- package/dist/utils/semantic-plan-gate.js.map +1 -0
- package/package.json +5 -43
- package/bin/smart-search.js +0 -79
- package/dist/templates/trellis/scripts/aggregate_retrieval_telemetry.py +0 -342
- package/dist/templates/trellis/scripts/batch_plan_envelope.py +0 -105
- package/vendor/smart-search/LICENSE +0 -21
- package/vendor/smart-search/README.md +0 -412
- package/vendor/smart-search/README.zh-CN.md +0 -430
- package/vendor/smart-search/npm/bin/smart-search.js +0 -63
- package/vendor/smart-search/npm/scripts/postinstall.js +0 -87
- package/vendor/smart-search/npm/scripts/resolve-prerelease-version.js +0 -108
- package/vendor/smart-search/npm/scripts/set-package-version.js +0 -35
- package/vendor/smart-search/npm/scripts/sync-python-version.js +0 -22
- package/vendor/smart-search/npm/scripts/test-wrapper-repair.js +0 -99
- package/vendor/smart-search/npm/scripts/test.js +0 -85
- package/vendor/smart-search/package.json +0 -42
- package/vendor/smart-search/pyproject.toml +0 -37
- package/vendor/smart-search/skills/smart-search-cli/SKILL.md +0 -387
- package/vendor/smart-search/skills/smart-search-cli/agents/openai.yaml +0 -3
- package/vendor/smart-search/skills/smart-search-cli/examples/batch-search.md +0 -98
- package/vendor/smart-search/skills/smart-search-cli/examples/evidence-gathering.md +0 -89
- package/vendor/smart-search/skills/smart-search-cli/references/cli-contract.md +0 -337
- package/vendor/smart-search/src/smart_search/__init__.py +0 -1
- package/vendor/smart-search/src/smart_search/assets/skills/smart-search-cli/SKILL.md +0 -387
- package/vendor/smart-search/src/smart_search/assets/skills/smart-search-cli/agents/openai.yaml +0 -3
- package/vendor/smart-search/src/smart_search/assets/skills/smart-search-cli/examples/batch-search.md +0 -98
- package/vendor/smart-search/src/smart_search/assets/skills/smart-search-cli/examples/evidence-gathering.md +0 -89
- package/vendor/smart-search/src/smart_search/assets/skills/smart-search-cli/references/cli-contract.md +0 -337
- package/vendor/smart-search/src/smart_search/cli.py +0 -2003
- package/vendor/smart-search/src/smart_search/config.py +0 -580
- package/vendor/smart-search/src/smart_search/logger.py +0 -43
- package/vendor/smart-search/src/smart_search/providers/__init__.py +0 -16
- package/vendor/smart-search/src/smart_search/providers/base.py +0 -41
- package/vendor/smart-search/src/smart_search/providers/context7.py +0 -141
- package/vendor/smart-search/src/smart_search/providers/exa.py +0 -206
- package/vendor/smart-search/src/smart_search/providers/jina.py +0 -136
- package/vendor/smart-search/src/smart_search/providers/openai_compatible.py +0 -370
- package/vendor/smart-search/src/smart_search/providers/zhipu.py +0 -143
- package/vendor/smart-search/src/smart_search/service.py +0 -2865
- package/vendor/smart-search/src/smart_search/sources.py +0 -429
- package/vendor/smart-search/src/smart_search/utils.py +0 -220
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"""
|
|
3
3
|
Deterministic codebase retrieval intent router (Python template).
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
get_context retrieval-pack flows. Does not invoke rg, MCP, or network tools.
|
|
5
|
+
Shared contract with the Trellis CLI router; used by hooks, route_codebase_retrieval.py,
|
|
6
|
+
and get_context retrieval-pack flows. Does not invoke rg, MCP, or network tools.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
from __future__ import annotations
|
|
@@ -13,6 +13,12 @@ import re
|
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
from typing import Any
|
|
15
15
|
|
|
16
|
+
from .cursor_retrieval_env import (
|
|
17
|
+
ENV_BYOK,
|
|
18
|
+
detect_cursor_retrieval_env,
|
|
19
|
+
semantic_route_spec,
|
|
20
|
+
)
|
|
21
|
+
|
|
16
22
|
ROUTER_VERSION = 2
|
|
17
23
|
|
|
18
24
|
PLATFORM_CURSOR = "cursor"
|
|
@@ -439,11 +445,32 @@ def _large_project(project_file_count: int | None) -> bool:
|
|
|
439
445
|
return project_file_count > 2000
|
|
440
446
|
|
|
441
447
|
|
|
448
|
+
def _platform_semantic_route(
|
|
449
|
+
*,
|
|
450
|
+
base_rationale: str,
|
|
451
|
+
cursor_env: str,
|
|
452
|
+
) -> dict[str, object]:
|
|
453
|
+
spec = semantic_route_spec(cursor_env)
|
|
454
|
+
suffix = str(spec.get("rationale_suffix", ""))
|
|
455
|
+
commands = spec.get("commands")
|
|
456
|
+
cmd_list = list(commands) if isinstance(commands, list) else []
|
|
457
|
+
return {
|
|
458
|
+
"id": "platform-semantic",
|
|
459
|
+
"role": "semantic",
|
|
460
|
+
"sourceFamily": "platform-semantic",
|
|
461
|
+
"commands": cmd_list,
|
|
462
|
+
"rationale": base_rationale + suffix,
|
|
463
|
+
"platformNative": bool(spec.get("platformNative", False)),
|
|
464
|
+
"semanticBackend": spec.get("semanticBackend"),
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
|
|
442
468
|
def _ordered_routes(
|
|
443
469
|
intents: list[dict[str, object]],
|
|
444
470
|
include_optional_adapters: bool,
|
|
445
471
|
*,
|
|
446
472
|
project_file_count: int | None = None,
|
|
473
|
+
cursor_env: str | None = None,
|
|
447
474
|
) -> list[dict[str, object]]:
|
|
448
475
|
ids = {str(item["id"]) for item in intents}
|
|
449
476
|
active = list(ids)
|
|
@@ -459,6 +486,7 @@ def _ordered_routes(
|
|
|
459
486
|
conceptual_primary = conceptual and not preserve and not exact_primary_first
|
|
460
487
|
large = _large_project(project_file_count)
|
|
461
488
|
semantic_promoted = False
|
|
489
|
+
cenv = cursor_env or detect_cursor_retrieval_env()
|
|
462
490
|
|
|
463
491
|
routes: list[dict[str, object]] = []
|
|
464
492
|
|
|
@@ -542,14 +570,7 @@ def _ordered_routes(
|
|
|
542
570
|
if policy
|
|
543
571
|
else "Conceptual query without exact signals; semantic recall before exact rg narrowing."
|
|
544
572
|
)
|
|
545
|
-
append(
|
|
546
|
-
"id": "platform-semantic",
|
|
547
|
-
"role": "semantic",
|
|
548
|
-
"sourceFamily": "platform-semantic",
|
|
549
|
-
"commands": ["cursor @codebase or built-in semantic search"],
|
|
550
|
-
"rationale": semantic_rationale + " (Cursor built-in semantic search)",
|
|
551
|
-
"platformNative": True,
|
|
552
|
-
})
|
|
573
|
+
append(_platform_semantic_route(base_rationale=semantic_rationale, cursor_env=cenv))
|
|
553
574
|
semantic_promoted = True
|
|
554
575
|
append({
|
|
555
576
|
"id": "exact-rg-primary",
|
|
@@ -638,24 +659,25 @@ def _ordered_routes(
|
|
|
638
659
|
})
|
|
639
660
|
append({
|
|
640
661
|
"id": "lsp-navigation",
|
|
641
|
-
"role": "
|
|
642
|
-
"sourceFamily": "
|
|
643
|
-
"commands": [
|
|
662
|
+
"role": "ast",
|
|
663
|
+
"sourceFamily": "codegraph",
|
|
664
|
+
"commands": [
|
|
665
|
+
"codegraph_node <symbol> --includeCode",
|
|
666
|
+
"codegraph_search <symbol>",
|
|
667
|
+
],
|
|
644
668
|
"rationale": (
|
|
645
|
-
"
|
|
646
|
-
"
|
|
669
|
+
"Definition/reference via codegraph (Cursor Agent does not expose "
|
|
670
|
+
"GO_TO_DEFINITION); corroborate with Read on returned line ranges."
|
|
647
671
|
),
|
|
648
|
-
"platformNative":
|
|
672
|
+
"platformNative": False,
|
|
649
673
|
})
|
|
650
674
|
if not semantic_promoted:
|
|
651
|
-
append(
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
"platformNative": True,
|
|
658
|
-
})
|
|
675
|
+
append(
|
|
676
|
+
_platform_semantic_route(
|
|
677
|
+
base_rationale="Semantic recall for conceptual narrowing.",
|
|
678
|
+
cursor_env=cenv,
|
|
679
|
+
)
|
|
680
|
+
)
|
|
659
681
|
|
|
660
682
|
append({
|
|
661
683
|
"id": "verification-source-git-tests",
|
|
@@ -678,6 +700,8 @@ def _fallback_hints(
|
|
|
678
700
|
intents: list[dict[str, object]],
|
|
679
701
|
include_optional_adapters: bool,
|
|
680
702
|
routes: list[dict[str, object]],
|
|
703
|
+
*,
|
|
704
|
+
cursor_env: str | None = None,
|
|
681
705
|
) -> list[dict[str, object]]:
|
|
682
706
|
hints: list[dict[str, object]] = [
|
|
683
707
|
{
|
|
@@ -688,7 +712,22 @@ def _fallback_hints(
|
|
|
688
712
|
if not include_optional_adapters:
|
|
689
713
|
hints.append({
|
|
690
714
|
"when": "codebase-retrieval not selected",
|
|
691
|
-
"action": "Skip optional AST/
|
|
715
|
+
"action": "Skip optional AST/semantic routes; use exact search and verification.",
|
|
716
|
+
"replacesRole": "semantic",
|
|
717
|
+
})
|
|
718
|
+
cenv = cursor_env or detect_cursor_retrieval_env()
|
|
719
|
+
if cenv == ENV_BYOK:
|
|
720
|
+
hints.append({
|
|
721
|
+
"when": "built-in @codebase / SemanticSearch not in agent tool list",
|
|
722
|
+
"action": (
|
|
723
|
+
"Use fast_context_search (fast-context MCP) per platform-semantic route; "
|
|
724
|
+
"do not use WebSearch for codebase questions."
|
|
725
|
+
),
|
|
726
|
+
"replacesRole": "semantic",
|
|
727
|
+
})
|
|
728
|
+
hints.append({
|
|
729
|
+
"when": "DEEP_SEARCH not available for wide cross-cutting explore",
|
|
730
|
+
"action": "Use Task subagent (explore), then Grep/codegraph/Read to verify.",
|
|
692
731
|
"replacesRole": "semantic",
|
|
693
732
|
})
|
|
694
733
|
if any(str(item["id"]) == INTENT_POLICY for item in intents):
|
|
@@ -716,8 +755,8 @@ def _fallback_hints(
|
|
|
716
755
|
"(or only trap hits) before final Top-1"
|
|
717
756
|
),
|
|
718
757
|
"action": (
|
|
719
|
-
"Use
|
|
720
|
-
"then narrow with rg on returned keywords and paths."
|
|
758
|
+
"Use fast_context_search (BYOK) or Cursor built-in semantic search (Native) "
|
|
759
|
+
"per platform-semantic route, then narrow with rg on returned keywords and paths."
|
|
721
760
|
),
|
|
722
761
|
"replacesRole": "semantic",
|
|
723
762
|
})
|
|
@@ -754,26 +793,33 @@ def route_codebase_retrieval(
|
|
|
754
793
|
*,
|
|
755
794
|
codebase_retrieval_selected: bool = True,
|
|
756
795
|
project_file_count: int | None = None,
|
|
796
|
+
cursor_env: str | None = None,
|
|
757
797
|
) -> dict[str, object]:
|
|
758
798
|
"""Return the shared evidence envelope with router-owned fields populated."""
|
|
759
799
|
normalized = _normalize_query(query)
|
|
760
800
|
include_optional = codebase_retrieval_selected
|
|
801
|
+
cenv = cursor_env or detect_cursor_retrieval_env()
|
|
761
802
|
if not normalized:
|
|
762
803
|
intents = [
|
|
763
804
|
_intent(INTENT_EXACT, "General codebase (exact baseline)", ["empty-query"], "low", True)
|
|
764
805
|
]
|
|
765
806
|
empty_routes = _ordered_routes(
|
|
766
|
-
intents,
|
|
807
|
+
intents,
|
|
808
|
+
include_optional,
|
|
767
809
|
project_file_count=project_file_count,
|
|
810
|
+
cursor_env=cenv,
|
|
768
811
|
)
|
|
769
812
|
return {
|
|
770
813
|
"version": ROUTER_VERSION,
|
|
771
814
|
"query": normalized,
|
|
815
|
+
"cursorEnv": cenv,
|
|
772
816
|
"intents": intents,
|
|
773
817
|
"routes": empty_routes,
|
|
774
818
|
"adapterState": [],
|
|
775
819
|
"freshness": [],
|
|
776
|
-
"fallback": _fallback_hints(
|
|
820
|
+
"fallback": _fallback_hints(
|
|
821
|
+
intents, include_optional, empty_routes, cursor_env=cenv
|
|
822
|
+
),
|
|
777
823
|
"warnings": ["Empty query; only baseline exact route is emitted."],
|
|
778
824
|
"verification": _base_verification(),
|
|
779
825
|
"projectFileCount": project_file_count,
|
|
@@ -781,17 +827,20 @@ def route_codebase_retrieval(
|
|
|
781
827
|
|
|
782
828
|
intents = _classify_intents(normalized)
|
|
783
829
|
routes = _ordered_routes(
|
|
784
|
-
intents,
|
|
830
|
+
intents,
|
|
831
|
+
include_optional,
|
|
785
832
|
project_file_count=project_file_count,
|
|
833
|
+
cursor_env=cenv,
|
|
786
834
|
)
|
|
787
835
|
return {
|
|
788
836
|
"version": ROUTER_VERSION,
|
|
789
837
|
"query": normalized,
|
|
838
|
+
"cursorEnv": cenv,
|
|
790
839
|
"intents": intents,
|
|
791
840
|
"routes": routes,
|
|
792
841
|
"adapterState": [],
|
|
793
842
|
"freshness": [],
|
|
794
|
-
"fallback": _fallback_hints(intents, include_optional, routes),
|
|
843
|
+
"fallback": _fallback_hints(intents, include_optional, routes, cursor_env=cenv),
|
|
795
844
|
"warnings": _warnings(intents),
|
|
796
845
|
"verification": _verification_for_intents(intents),
|
|
797
846
|
"projectFileCount": project_file_count,
|
|
@@ -289,7 +289,7 @@ def get_packages(repo_root: Path | None = None) -> dict[str, dict] | None:
|
|
|
289
289
|
or None if not configured (single-repo mode).
|
|
290
290
|
|
|
291
291
|
Example return:
|
|
292
|
-
{"
|
|
292
|
+
{"api": {"path": "packages/api"}, "web": {"path": "packages/web"}}
|
|
293
293
|
"""
|
|
294
294
|
config = _load_config(repo_root)
|
|
295
295
|
packages = config.get("packages")
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Detect Cursor Native vs Cursor++ BYOK for retrieval routing."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
ENV_NATIVE = "native"
|
|
11
|
+
ENV_BYOK = "byok"
|
|
12
|
+
ENV_UNKNOWN = "unknown"
|
|
13
|
+
|
|
14
|
+
CursorRetrievalEnv = str # native | byok | unknown
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def ccursor_home() -> Path:
|
|
18
|
+
env = os.environ.get("TRELLIS_CCURSOR_HOME", "").strip()
|
|
19
|
+
if env:
|
|
20
|
+
return Path(env).expanduser()
|
|
21
|
+
return Path.home() / ".ccursor"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def detect_cursor_retrieval_env() -> CursorRetrievalEnv:
|
|
25
|
+
"""Return native | byok | unknown.
|
|
26
|
+
|
|
27
|
+
Override: TRELLIS_CURSOR_BYOK=1|0
|
|
28
|
+
"""
|
|
29
|
+
info = detect_cursor_retrieval_env_info()
|
|
30
|
+
env = info.get("env")
|
|
31
|
+
if env in (ENV_NATIVE, ENV_BYOK, ENV_UNKNOWN):
|
|
32
|
+
return str(env)
|
|
33
|
+
return ENV_UNKNOWN
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def detect_cursor_retrieval_env_info() -> dict[str, Any]:
|
|
37
|
+
"""Full detection record (for probes and envelopes)."""
|
|
38
|
+
env_override = os.environ.get("TRELLIS_CURSOR_BYOK", "").strip()
|
|
39
|
+
if env_override == "1":
|
|
40
|
+
return {"env": ENV_BYOK, "source": "env-override", "byokMode": 1}
|
|
41
|
+
if env_override == "0":
|
|
42
|
+
return {"env": ENV_NATIVE, "source": "env-override", "byokMode": 0}
|
|
43
|
+
|
|
44
|
+
routes_path = ccursor_home() / "routes.json"
|
|
45
|
+
if not routes_path.is_file():
|
|
46
|
+
return {
|
|
47
|
+
"env": ENV_UNKNOWN,
|
|
48
|
+
"source": "routes-not-found",
|
|
49
|
+
"byokMode": None,
|
|
50
|
+
"routes_path": str(routes_path),
|
|
51
|
+
}
|
|
52
|
+
try:
|
|
53
|
+
routes = json.loads(routes_path.read_text(encoding="utf-8"))
|
|
54
|
+
except (OSError, json.JSONDecodeError) as exc:
|
|
55
|
+
return {
|
|
56
|
+
"env": ENV_UNKNOWN,
|
|
57
|
+
"source": "routes-parse-error",
|
|
58
|
+
"byokMode": None,
|
|
59
|
+
"error": str(exc),
|
|
60
|
+
"routes_path": str(routes_path),
|
|
61
|
+
}
|
|
62
|
+
byok = routes.get("byokMode")
|
|
63
|
+
env = ENV_BYOK if byok == 1 else ENV_NATIVE if byok == 0 else ENV_UNKNOWN
|
|
64
|
+
redirect = routes.get("redirect", [])
|
|
65
|
+
return {
|
|
66
|
+
"env": env,
|
|
67
|
+
"source": "routes.json",
|
|
68
|
+
"byokMode": byok,
|
|
69
|
+
"routes_path": str(routes_path),
|
|
70
|
+
"redirect_endpoints": list(redirect) if isinstance(redirect, list) else [],
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def is_byok(env: CursorRetrievalEnv | None = None) -> bool:
|
|
75
|
+
return (env or detect_cursor_retrieval_env()) == ENV_BYOK
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def semantic_route_spec(cursor_env: CursorRetrievalEnv) -> dict[str, object]:
|
|
79
|
+
"""platform-semantic route fields for conceptual / optional semantic slots."""
|
|
80
|
+
if cursor_env == ENV_BYOK:
|
|
81
|
+
return {
|
|
82
|
+
"commands": ["fast_context_search (fast-context MCP)"],
|
|
83
|
+
"rationale_suffix": " Cursor++ BYOK: built-in semantic unavailable; fast-context MCP primary.",
|
|
84
|
+
"platformNative": False,
|
|
85
|
+
"semanticBackend": "fast-context-mcp",
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
"commands": ["cursor @codebase or built-in semantic search"],
|
|
89
|
+
"rationale_suffix": " Cursor built-in semantic search.",
|
|
90
|
+
"platformNative": True,
|
|
91
|
+
"semanticBackend": "cursor-builtin",
|
|
92
|
+
}
|
|
@@ -16,6 +16,7 @@ from .paths import get_repo_root
|
|
|
16
16
|
from .task_gates import (
|
|
17
17
|
build_spec_update_scaffold,
|
|
18
18
|
durable_learning_decision_status,
|
|
19
|
+
task_closeout_profile,
|
|
19
20
|
)
|
|
20
21
|
from .task_map import (
|
|
21
22
|
PARENT_TERMINAL_STATES,
|
|
@@ -31,7 +32,6 @@ _GLOBAL_CHILD_CONSTRAINTS = """General constraints:
|
|
|
31
32
|
- Stay inside your child scope and declared touch areas.
|
|
32
33
|
- Do not publish packages, push remotes, create tags, edit credentials, or change global/MCP configuration.
|
|
33
34
|
- Preserve explicit user approval for destructive, remote, credential-bearing, publish, push, tag, and global configuration actions.
|
|
34
|
-
- Keep template and dogfood copies synchronized when touching `.trellis/scripts` or Trellis CLI templates.
|
|
35
35
|
- Write `verify.md` and `handoff.md` in your child task directory.
|
|
36
36
|
- Handoff must include changed files, validation commands/results, residual risks, and parent integration notes.
|
|
37
37
|
- If you find a needed contract change, stop and report it to the parent instead of silently redefining shared state/gate semantics.
|
|
@@ -530,18 +530,29 @@ def build_review_report(
|
|
|
530
530
|
),
|
|
531
531
|
}
|
|
532
532
|
)
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
533
|
+
child_profile = task_closeout_profile(child_dir, child_data)
|
|
534
|
+
if child_profile == "full":
|
|
535
|
+
actions["gates"].append(
|
|
536
|
+
{
|
|
537
|
+
"task": "child",
|
|
538
|
+
"transition": "child-review",
|
|
539
|
+
"optional": False,
|
|
540
|
+
"hint": (
|
|
541
|
+
f"Required before accept: python ./.trellis/scripts/task.py record-gate {child_name} "
|
|
542
|
+
f"--transition child-review --gate code-review --result PASS "
|
|
543
|
+
f"--reviewer parent --evidence verify.md"
|
|
544
|
+
),
|
|
545
|
+
}
|
|
546
|
+
)
|
|
547
|
+
elif child_profile == "lite":
|
|
548
|
+
actions["gates"].append(
|
|
549
|
+
{
|
|
550
|
+
"task": "child",
|
|
551
|
+
"transition": "child-review",
|
|
552
|
+
"optional": True,
|
|
553
|
+
"hint": "Lite child: no child-review gate chain required.",
|
|
554
|
+
}
|
|
555
|
+
)
|
|
545
556
|
elif decision == "changes":
|
|
546
557
|
target = "changes"
|
|
547
558
|
errors.extend(
|
|
@@ -611,6 +622,7 @@ def build_review_report(
|
|
|
611
622
|
evidence,
|
|
612
623
|
ref,
|
|
613
624
|
reason,
|
|
625
|
+
current_state_override=sim_state,
|
|
614
626
|
)
|
|
615
627
|
errors.extend(step_errors)
|
|
616
628
|
if step_errors:
|
|
@@ -626,9 +638,9 @@ def build_review_report(
|
|
|
626
638
|
{
|
|
627
639
|
"task": "parent",
|
|
628
640
|
"transition": "parent-integrated",
|
|
629
|
-
"optional":
|
|
641
|
+
"optional": False,
|
|
630
642
|
"hint": (
|
|
631
|
-
f"python ./.trellis/scripts/task.py record-gate {parent_dir.name} "
|
|
643
|
+
f"Required before parent archive: python ./.trellis/scripts/task.py record-gate {parent_dir.name} "
|
|
632
644
|
f"--transition parent-integrated --gate integration-review --result PASS "
|
|
633
645
|
f"--reviewer parent --evidence task-map.md"
|
|
634
646
|
),
|
|
@@ -11,6 +11,7 @@ from __future__ import annotations
|
|
|
11
11
|
from datetime import datetime, timezone
|
|
12
12
|
from typing import Any
|
|
13
13
|
|
|
14
|
+
from common.cursor_retrieval_env import ENV_BYOK, detect_cursor_retrieval_env
|
|
14
15
|
from common.retrieval_evidence import (
|
|
15
16
|
SOURCE_ARTIFACT_SEARCH,
|
|
16
17
|
SOURCE_CODEBASE_EVIDENCE,
|
|
@@ -71,7 +72,6 @@ REQUIRED_ADAPTERS = frozenset({ADAPTER_RG, ADAPTER_VERIFICATION})
|
|
|
71
72
|
OPTIONAL_INTEGRATION_ADAPTERS = (
|
|
72
73
|
ADAPTER_CODEGRAPH,
|
|
73
74
|
ADAPTER_LSP,
|
|
74
|
-
ADAPTER_FAST_CONTEXT,
|
|
75
75
|
ADAPTER_MCP,
|
|
76
76
|
ADAPTER_BROWSER,
|
|
77
77
|
ADAPTER_NETWORK,
|
|
@@ -236,15 +236,11 @@ def build_adapter_states(
|
|
|
236
236
|
optional_integration_adapter_state(adapter=adapter, hints=hints)
|
|
237
237
|
)
|
|
238
238
|
|
|
239
|
-
# Platform-semantic: Cursor built-in semantic search (replaces fast-context)
|
|
240
239
|
states.append(
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
invoked=False,
|
|
246
|
-
reason="Platform-native semantic search on Cursor (e.g. @codebase); supersedes fast-context",
|
|
247
|
-
)
|
|
240
|
+
platform_semantic_adapter_state(router=router, hints=hints)
|
|
241
|
+
)
|
|
242
|
+
states.append(
|
|
243
|
+
fast_context_adapter_state(router=router, hints=hints)
|
|
248
244
|
)
|
|
249
245
|
|
|
250
246
|
states.append(
|
|
@@ -441,6 +437,101 @@ def codebase_adapter_state(
|
|
|
441
437
|
)
|
|
442
438
|
|
|
443
439
|
|
|
440
|
+
def resolve_cursor_env_for_adapter_metadata(
|
|
441
|
+
router: dict[str, Any] | None,
|
|
442
|
+
) -> str:
|
|
443
|
+
"""native | byok | unknown for retrieval-pack adapter reasons."""
|
|
444
|
+
router = router or {}
|
|
445
|
+
env = string_value(router.get("cursorEnv"))
|
|
446
|
+
if env in ("native", "byok", "unknown"):
|
|
447
|
+
return env
|
|
448
|
+
return detect_cursor_retrieval_env()
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def platform_semantic_adapter_state(
|
|
452
|
+
*,
|
|
453
|
+
router: dict[str, Any] | None,
|
|
454
|
+
hints: dict[str, dict[str, Any]],
|
|
455
|
+
) -> dict[str, object]:
|
|
456
|
+
hint = hints.get(ADAPTER_PLATFORM_SEMANTIC, {})
|
|
457
|
+
if hint:
|
|
458
|
+
return adapter_state_entry(
|
|
459
|
+
adapter=ADAPTER_PLATFORM_SEMANTIC,
|
|
460
|
+
state=resolve_hint_state(hints, ADAPTER_PLATFORM_SEMANTIC, default=STATE_SKIPPED),
|
|
461
|
+
required=False,
|
|
462
|
+
invoked=bool(hint.get("invoked")),
|
|
463
|
+
reason=string_value(hint.get("reason")) or "platform-semantic adapter hint",
|
|
464
|
+
)
|
|
465
|
+
env = resolve_cursor_env_for_adapter_metadata(router)
|
|
466
|
+
if env == ENV_BYOK:
|
|
467
|
+
reason = (
|
|
468
|
+
"Cursor++ BYOK: built-in codebase semantic often absent (Experiment D); "
|
|
469
|
+
"concept recall Primary is fast-context MCP per router cursorEnv"
|
|
470
|
+
)
|
|
471
|
+
state = STATE_UNAVAILABLE
|
|
472
|
+
elif env == "native":
|
|
473
|
+
reason = (
|
|
474
|
+
"Cursor Native: built-in codebase semantic (e.g. SemanticSearch / @codebase) "
|
|
475
|
+
"is Primary for concept recall"
|
|
476
|
+
)
|
|
477
|
+
state = STATE_AVAILABLE
|
|
478
|
+
else:
|
|
479
|
+
reason = (
|
|
480
|
+
"Cursor platform-semantic: Native uses built-in search; BYOK uses fast-context "
|
|
481
|
+
"when cursorEnv is byok (see cursor_retrieval_env)"
|
|
482
|
+
)
|
|
483
|
+
state = STATE_UNVERIFIED
|
|
484
|
+
return adapter_state_entry(
|
|
485
|
+
adapter=ADAPTER_PLATFORM_SEMANTIC,
|
|
486
|
+
state=state,
|
|
487
|
+
required=False,
|
|
488
|
+
invoked=False,
|
|
489
|
+
reason=reason,
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def fast_context_adapter_state(
|
|
494
|
+
*,
|
|
495
|
+
router: dict[str, Any] | None,
|
|
496
|
+
hints: dict[str, dict[str, Any]],
|
|
497
|
+
) -> dict[str, object]:
|
|
498
|
+
hint = hints.get(ADAPTER_FAST_CONTEXT, {})
|
|
499
|
+
if hint:
|
|
500
|
+
return adapter_state_entry(
|
|
501
|
+
adapter=ADAPTER_FAST_CONTEXT,
|
|
502
|
+
state=resolve_hint_state(hints, ADAPTER_FAST_CONTEXT, default=STATE_SKIPPED),
|
|
503
|
+
required=False,
|
|
504
|
+
invoked=bool(hint.get("invoked")),
|
|
505
|
+
reason=string_value(hint.get("reason")) or "fast-context-mcp adapter hint",
|
|
506
|
+
)
|
|
507
|
+
env = resolve_cursor_env_for_adapter_metadata(router)
|
|
508
|
+
if env == ENV_BYOK:
|
|
509
|
+
reason = (
|
|
510
|
+
"Cursor++ BYOK: fast_context_search is compliant Primary for concept recall "
|
|
511
|
+
"(select codebase-retrieval at init for .cursor/mcp.json fast-context entry)"
|
|
512
|
+
)
|
|
513
|
+
state = STATE_AVAILABLE
|
|
514
|
+
elif env == "native":
|
|
515
|
+
reason = (
|
|
516
|
+
"Cursor Native: prefer built-in platform-semantic; fast-context is optional "
|
|
517
|
+
"and misuse when plan requires native semantic"
|
|
518
|
+
)
|
|
519
|
+
state = STATE_SKIPPED
|
|
520
|
+
else:
|
|
521
|
+
reason = (
|
|
522
|
+
"fast-context MCP: required for BYOK concept recall on Cursor when "
|
|
523
|
+
"codebase-retrieval capability is selected"
|
|
524
|
+
)
|
|
525
|
+
state = STATE_UNVERIFIED
|
|
526
|
+
return adapter_state_entry(
|
|
527
|
+
adapter=ADAPTER_FAST_CONTEXT,
|
|
528
|
+
state=state,
|
|
529
|
+
required=False,
|
|
530
|
+
invoked=False,
|
|
531
|
+
reason=reason,
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
|
|
444
535
|
def optional_integration_adapter_state(
|
|
445
536
|
*,
|
|
446
537
|
adapter: str,
|