@blxzer/cursor-trellis 0.4.2 → 0.4.3
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 +24 -0
- package/README.md +23 -14
- package/README.zh-CN.md +14 -10
- package/bin/smart-search.js +10 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +36 -15
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +42 -153
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/migrate.d.ts +10 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +38 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/update.d.ts +5 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +137 -40
- package/dist/commands/update.js.map +1 -1
- package/dist/configurators/cursor.d.ts +2 -1
- package/dist/configurators/cursor.d.ts.map +1 -1
- package/dist/configurators/cursor.js +4 -2
- package/dist/configurators/cursor.js.map +1 -1
- package/dist/configurators/index.js +4 -4
- package/dist/configurators/index.js.map +1 -1
- package/dist/configurators/shared.d.ts +8 -0
- package/dist/configurators/shared.d.ts.map +1 -1
- package/dist/configurators/shared.js +27 -1
- package/dist/configurators/shared.js.map +1 -1
- package/dist/configurators/workflow.d.ts +0 -9
- package/dist/configurators/workflow.d.ts.map +1 -1
- package/dist/configurators/workflow.js +2 -4
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/constants/paths.d.ts +9 -0
- package/dist/constants/paths.d.ts.map +1 -1
- package/dist/constants/paths.js +13 -0
- package/dist/constants/paths.js.map +1 -1
- package/dist/migrations/manifests/0.3.0.json +1 -1
- package/dist/templates/common/bundled-skills/cstl-meta/references/platform-files/skills-and-commands.md +2 -4
- package/dist/templates/common/bundled-skills/cstl-skill-creator/SKILL.md +10 -7
- package/dist/templates/common/bundled-skills/cstl-skill-creator/references/authoring-rules.md +93 -19
- package/dist/templates/common/bundled-skills/cstl-skill-creator/references/general-authoring.md +189 -0
- package/dist/templates/common/bundled-skills/cstl-skill-creator/references/review-checklist.md +10 -5
- package/dist/templates/common/commands/continue.md +5 -4
- package/dist/templates/common/index.d.ts +20 -0
- package/dist/templates/common/index.d.ts.map +1 -1
- package/dist/templates/common/index.js +21 -2
- package/dist/templates/common/index.js.map +1 -1
- package/dist/templates/common/optional-skills/chrome-cdp/SKILL.md +179 -0
- package/dist/templates/common/optional-skills/chrome-cdp/examples/fetch-hook-api-capture.md +149 -0
- package/dist/templates/common/optional-skills/chrome-cdp/scripts/cdp.mjs +903 -0
- package/dist/templates/cursor/agents/cstl-research.md +1 -1
- package/dist/templates/cursor/fixtures/expected-rules.d.ts +1 -1
- package/dist/templates/cursor/fixtures/expected-rules.d.ts.map +1 -1
- package/dist/templates/cursor/fixtures/expected-rules.js +7 -24
- package/dist/templates/cursor/fixtures/expected-rules.js.map +1 -1
- package/dist/templates/cursor/hooks.json +4 -0
- package/dist/templates/cursor/index.d.ts +1 -1
- package/dist/templates/cursor/index.js +1 -1
- package/dist/templates/cursor/rules/cstl-bootstrap.mdc +17 -0
- package/dist/templates/markdown/agents.md +15 -10
- package/dist/templates/markdown/framework/cursor-native-modes-guide.md.txt +12 -9
- package/dist/templates/markdown/framework/cursor-subagent-policy.md.txt +62 -126
- package/dist/templates/markdown/framework/dogfood-only-surfaces.md.txt +4 -6
- package/dist/templates/markdown/framework/execution-strategy.md.txt +2 -0
- package/dist/templates/markdown/framework/index.md.txt +4 -0
- package/dist/templates/markdown/framework/internal-skills-cursor-reachability.md.txt +4 -3
- package/dist/templates/markdown/framework/middleware-protocol.md.txt +83 -0
- package/dist/templates/markdown/framework/parallel-first-execution.md.txt +78 -0
- package/dist/templates/markdown/framework/release-boundary.md.txt +30 -0
- package/dist/templates/markdown/framework/retrieval-daily-guide.md.txt +1 -1
- package/dist/templates/markdown/framework/upgrade.md.txt +15 -0
- package/dist/templates/markdown/index.d.ts +4 -0
- package/dist/templates/markdown/index.d.ts.map +1 -1
- package/dist/templates/markdown/index.js +17 -0
- package/dist/templates/markdown/index.js.map +1 -1
- package/dist/templates/markdown/spec/guides/index.md.txt +0 -6
- package/dist/templates/shared-hooks/event-bridge.py +60 -0
- package/dist/templates/shared-hooks/index.d.ts +1 -1
- package/dist/templates/shared-hooks/index.d.ts.map +1 -1
- package/dist/templates/shared-hooks/index.js +1 -0
- package/dist/templates/shared-hooks/index.js.map +1 -1
- package/dist/templates/shared-hooks/session-start.py +18 -1
- package/dist/templates/trellis/CONTEXT.md +63 -3
- package/dist/templates/trellis/gitignore.txt +39 -39
- package/dist/templates/trellis/index.d.ts +12 -0
- package/dist/templates/trellis/index.d.ts.map +1 -1
- package/dist/templates/trellis/index.js +73 -15
- package/dist/templates/trellis/index.js.map +1 -1
- package/dist/templates/trellis/pool/README.md +12 -3
- package/dist/templates/trellis/pool/plan.md +24 -5
- package/dist/templates/trellis/scripts/common/adapter_middleware.py +158 -0
- package/dist/templates/trellis/scripts/common/artifact_locale.py +12 -3
- package/dist/templates/trellis/scripts/common/cursor_retrieval_env.py +5 -2
- package/dist/templates/trellis/scripts/common/full_quality.py +237 -0
- package/dist/templates/trellis/scripts/common/git.py +6 -0
- package/dist/templates/trellis/scripts/common/git_context.py +17 -5
- package/dist/templates/trellis/scripts/common/kernel_command.py +367 -0
- package/dist/templates/trellis/scripts/common/lite_context.py +280 -0
- package/dist/templates/trellis/scripts/common/ondemand_topology.py +225 -0
- package/dist/templates/trellis/scripts/common/parent_orchestration.py +1 -1
- package/dist/templates/trellis/scripts/common/pool_store.py +16 -4
- package/dist/templates/trellis/scripts/common/retrieval_agent_instructions.py +2 -2
- package/dist/templates/trellis/scripts/common/session_context.py +28 -2
- package/dist/templates/trellis/scripts/common/task_gates.py +73 -12
- package/dist/templates/trellis/scripts/common/task_map.py +42 -9
- package/dist/templates/trellis/scripts/common/task_store.py +286 -56
- package/dist/templates/trellis/scripts/common/test_adapter_middleware.py +56 -0
- package/dist/templates/trellis/scripts/common/test_depends_mode_block.py +9 -0
- package/dist/templates/trellis/scripts/common/test_full_quality.py +197 -0
- package/dist/templates/trellis/scripts/common/test_kernel_command.py +326 -0
- package/dist/templates/trellis/scripts/common/test_lite_path.py +190 -0
- package/dist/templates/trellis/scripts/common/test_ondemand_topology.py +122 -0
- package/dist/templates/trellis/scripts/common/test_pool_store.py +17 -0
- package/dist/templates/trellis/scripts/common/test_task_store_kernel_patch.py +163 -0
- package/dist/templates/trellis/scripts/common/workflow_phase.py +3 -0
- package/dist/templates/trellis/scripts/get_context.py +1 -0
- package/dist/templates/trellis/scripts/pool.py +5 -0
- package/dist/templates/trellis/scripts/task.py +83 -7
- package/dist/templates/trellis/workflow.md +100 -18
- package/dist/utils/cursor-retrieval-env.d.ts +2 -1
- package/dist/utils/cursor-retrieval-env.d.ts.map +1 -1
- package/dist/utils/cursor-retrieval-env.js +3 -2
- package/dist/utils/cursor-retrieval-env.js.map +1 -1
- package/dist/utils/cursor2plus-residue-cleanup.d.ts +38 -0
- package/dist/utils/cursor2plus-residue-cleanup.d.ts.map +1 -0
- package/dist/utils/cursor2plus-residue-cleanup.js +145 -0
- package/dist/utils/cursor2plus-residue-cleanup.js.map +1 -0
- package/dist/utils/manifest-prune.d.ts.map +1 -1
- package/dist/utils/manifest-prune.js +7 -2
- package/dist/utils/manifest-prune.js.map +1 -1
- package/dist/utils/p36-upgrade.d.ts +62 -0
- package/dist/utils/p36-upgrade.d.ts.map +1 -0
- package/dist/utils/p36-upgrade.js +160 -0
- package/dist/utils/p36-upgrade.js.map +1 -0
- package/dist/utils/project-capabilities.d.ts +1 -12
- package/dist/utils/project-capabilities.d.ts.map +1 -1
- package/dist/utils/project-capabilities.js +3 -100
- package/dist/utils/project-capabilities.js.map +1 -1
- package/dist/utils/readiness.d.ts +10 -0
- package/dist/utils/readiness.d.ts.map +1 -1
- package/dist/utils/readiness.js +58 -26
- package/dist/utils/readiness.js.map +1 -1
- package/dist/utils/retrieval-agent-instructions.js +1 -1
- package/dist/utils/retrieval-agent-instructions.js.map +1 -1
- package/dist/utils/template-hash.d.ts.map +1 -1
- package/dist/utils/template-hash.js +11 -1
- package/dist/utils/template-hash.js.map +1 -1
- package/dist/utils/uninstall-scrubbers.d.ts.map +1 -1
- package/dist/utils/uninstall-scrubbers.js +52 -14
- package/dist/utils/uninstall-scrubbers.js.map +1 -1
- package/dist/utils/update-rollout-report.d.ts +14 -0
- package/dist/utils/update-rollout-report.d.ts.map +1 -1
- package/dist/utils/update-rollout-report.js +1 -0
- package/dist/utils/update-rollout-report.js.map +1 -1
- package/dist/utils/workflow-ownership.d.ts +1 -1
- package/dist/utils/workflow-ownership.js +4 -4
- package/dist/utils/workflow-ownership.js.map +1 -1
- package/package.json +5 -4
- package/scripts/postinstall.js +6 -7
- package/dist/commands/campaign/canvas-render.d.ts +0 -68
- package/dist/commands/campaign/canvas-render.d.ts.map +0 -1
- package/dist/commands/campaign/canvas-render.js +0 -414
- package/dist/commands/campaign/canvas-render.js.map +0 -1
- package/dist/commands/campaign/compose.d.ts +0 -15
- package/dist/commands/campaign/compose.d.ts.map +0 -1
- package/dist/commands/campaign/compose.js +0 -110
- package/dist/commands/campaign/compose.js.map +0 -1
- package/dist/commands/campaign/index.d.ts +0 -13
- package/dist/commands/campaign/index.d.ts.map +0 -1
- package/dist/commands/campaign/index.js +0 -134
- package/dist/commands/campaign/index.js.map +0 -1
- package/dist/commands/campaign/kind-map.d.ts +0 -6
- package/dist/commands/campaign/kind-map.d.ts.map +0 -1
- package/dist/commands/campaign/kind-map.js +0 -21
- package/dist/commands/campaign/kind-map.js.map +0 -1
- package/dist/commands/campaign/mcp-server.d.ts +0 -6
- package/dist/commands/campaign/mcp-server.d.ts.map +0 -1
- package/dist/commands/campaign/mcp-server.js +0 -167
- package/dist/commands/campaign/mcp-server.js.map +0 -1
- package/dist/commands/campaign/render.d.ts +0 -5
- package/dist/commands/campaign/render.d.ts.map +0 -1
- package/dist/commands/campaign/render.js +0 -103
- package/dist/commands/campaign/render.js.map +0 -1
- package/dist/commands/campaign/trellis-load.d.ts +0 -13
- package/dist/commands/campaign/trellis-load.d.ts.map +0 -1
- package/dist/commands/campaign/trellis-load.js +0 -122
- package/dist/commands/campaign/trellis-load.js.map +0 -1
- package/dist/commands/campaign/types.d.ts +0 -61
- package/dist/commands/campaign/types.d.ts.map +0 -1
- package/dist/commands/campaign/types.js +0 -3
- package/dist/commands/campaign/types.js.map +0 -1
- package/dist/commands/goal/index.d.ts +0 -3
- package/dist/commands/goal/index.d.ts.map +0 -1
- package/dist/commands/goal/index.js +0 -159
- package/dist/commands/goal/index.js.map +0 -1
- package/dist/commands/goal/review.d.ts +0 -6
- package/dist/commands/goal/review.d.ts.map +0 -1
- package/dist/commands/goal/review.js +0 -28
- package/dist/commands/goal/review.js.map +0 -1
- package/dist/commands/rpc/client.d.ts +0 -51
- package/dist/commands/rpc/client.d.ts.map +0 -1
- package/dist/commands/rpc/client.js +0 -147
- package/dist/commands/rpc/client.js.map +0 -1
- package/dist/commands/rpc/index.d.ts +0 -10
- package/dist/commands/rpc/index.d.ts.map +0 -1
- package/dist/commands/rpc/index.js +0 -157
- package/dist/commands/rpc/index.js.map +0 -1
- package/dist/commands/rpc/serve.d.ts +0 -23
- package/dist/commands/rpc/serve.d.ts.map +0 -1
- package/dist/commands/rpc/serve.js +0 -60
- package/dist/commands/rpc/serve.js.map +0 -1
- package/dist/commands/rpc/smoke.d.ts +0 -16
- package/dist/commands/rpc/smoke.d.ts.map +0 -1
- package/dist/commands/rpc/smoke.js +0 -92
- package/dist/commands/rpc/smoke.js.map +0 -1
- package/dist/commands/sdk/index.d.ts +0 -9
- package/dist/commands/sdk/index.d.ts.map +0 -1
- package/dist/commands/sdk/index.js +0 -58
- package/dist/commands/sdk/index.js.map +0 -1
- package/dist/commands/sdk/run.d.ts +0 -42
- package/dist/commands/sdk/run.d.ts.map +0 -1
- package/dist/commands/sdk/run.js +0 -220
- package/dist/commands/sdk/run.js.map +0 -1
- package/dist/commands/sdk/status.d.ts +0 -14
- package/dist/commands/sdk/status.d.ts.map +0 -1
- package/dist/commands/sdk/status.js +0 -69
- package/dist/commands/sdk/status.js.map +0 -1
- package/dist/configurators/cursor2plus-local.d.ts +0 -6
- package/dist/configurators/cursor2plus-local.d.ts.map +0 -1
- package/dist/configurators/cursor2plus-local.js +0 -21
- package/dist/configurators/cursor2plus-local.js.map +0 -1
- package/dist/goal/action-packet.d.ts +0 -89
- package/dist/goal/action-packet.d.ts.map +0 -1
- package/dist/goal/action-packet.js +0 -113
- package/dist/goal/action-packet.js.map +0 -1
- package/dist/goal/audit.d.ts +0 -14
- package/dist/goal/audit.d.ts.map +0 -1
- package/dist/goal/audit.js +0 -12
- package/dist/goal/audit.js.map +0 -1
- package/dist/goal/constants.d.ts +0 -26
- package/dist/goal/constants.d.ts.map +0 -1
- package/dist/goal/constants.js +0 -24
- package/dist/goal/constants.js.map +0 -1
- package/dist/goal/paths.d.ts +0 -8
- package/dist/goal/paths.d.ts.map +0 -1
- package/dist/goal/paths.js +0 -36
- package/dist/goal/paths.js.map +0 -1
- package/dist/goal/preflight.d.ts +0 -21
- package/dist/goal/preflight.d.ts.map +0 -1
- package/dist/goal/preflight.js +0 -97
- package/dist/goal/preflight.js.map +0 -1
- package/dist/goal/review-seam.d.ts +0 -44
- package/dist/goal/review-seam.d.ts.map +0 -1
- package/dist/goal/review-seam.js +0 -153
- package/dist/goal/review-seam.js.map +0 -1
- package/dist/goal/reviewer-rules.d.ts +0 -13
- package/dist/goal/reviewer-rules.d.ts.map +0 -1
- package/dist/goal/reviewer-rules.js +0 -153
- package/dist/goal/reviewer-rules.js.map +0 -1
- package/dist/goal/reviewer.d.ts +0 -9
- package/dist/goal/reviewer.d.ts.map +0 -1
- package/dist/goal/reviewer.js +0 -54
- package/dist/goal/reviewer.js.map +0 -1
- package/dist/goal/runtime.d.ts +0 -32
- package/dist/goal/runtime.d.ts.map +0 -1
- package/dist/goal/runtime.js +0 -242
- package/dist/goal/runtime.js.map +0 -1
- package/dist/goal/sdk-client.d.ts +0 -10
- package/dist/goal/sdk-client.d.ts.map +0 -1
- package/dist/goal/sdk-client.js +0 -34
- package/dist/goal/sdk-client.js.map +0 -1
- package/dist/goal/state.d.ts +0 -40
- package/dist/goal/state.d.ts.map +0 -1
- package/dist/goal/state.js +0 -37
- package/dist/goal/state.js.map +0 -1
- package/dist/goal/task-triggers.d.ts +0 -15
- package/dist/goal/task-triggers.d.ts.map +0 -1
- package/dist/goal/task-triggers.js +0 -23
- package/dist/goal/task-triggers.js.map +0 -1
- package/dist/goal/walls.d.ts +0 -12
- package/dist/goal/walls.d.ts.map +0 -1
- package/dist/goal/walls.js +0 -65
- package/dist/goal/walls.js.map +0 -1
- package/dist/goal/worker-prompt.d.ts +0 -13
- package/dist/goal/worker-prompt.d.ts.map +0 -1
- package/dist/goal/worker-prompt.js +0 -41
- package/dist/goal/worker-prompt.js.map +0 -1
- package/dist/goal/worker.d.ts +0 -42
- package/dist/goal/worker.d.ts.map +0 -1
- package/dist/goal/worker.js +0 -180
- package/dist/goal/worker.js.map +0 -1
- package/dist/templates/common/bundled-skills/cstl-cursor2plus-setup/SKILL.md +0 -63
- package/dist/templates/cursor/commands/cursor2plus-setup.md +0 -82
- package/dist/templates/cursor/rules/cstl-cursor-modes.mdc +0 -32
- package/dist/templates/cursor/rules/cstl-session-rename.mdc +0 -31
- package/dist/templates/cursor/rules/cstl-subagent-dispatch.mdc +0 -34
- package/dist/templates/cursor/rules/cstl-triage.mdc +0 -36
- package/dist/templates/cursor/rules/retrieval-routing.mdc +0 -78
- package/dist/templates/trellis/local/README.md +0 -85
- package/dist/templates/trellis/local/config.local.json.example +0 -6
- package/dist/templates/trellis/local/index.d.ts +0 -8
- package/dist/templates/trellis/local/index.d.ts.map +0 -1
- package/dist/templates/trellis/local/index.js +0 -15
- package/dist/templates/trellis/local/index.js.map +0 -1
- package/dist/templates/trellis/local/patch_wpelc8.py +0 -421
- package/dist/templates/trellis/local/smoke.py +0 -94
- package/dist/templates/trellis/local/subagent-models.json.example +0 -4
- package/dist/templates/trellis/local/trellis-task-models.json.example +0 -10
- package/dist/templates/trellis/local/trellis-task-models.json5.example +0 -45
- package/dist/templates/trellis/local/trellis_task_models_config.py +0 -200
- package/dist/utils/cursor-sdk-gate.d.ts +0 -10
- package/dist/utils/cursor-sdk-gate.d.ts.map +0 -1
- package/dist/utils/cursor-sdk-gate.js +0 -32
- package/dist/utils/cursor-sdk-gate.js.map +0 -1
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Trellis codebase retrieval on Cursor — follow router-derived plans; Rules are the primary injection channel (not sessionStart hooks)"
|
|
3
|
-
alwaysApply: true
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Codebase retrieval routing (Cursor)
|
|
7
|
-
|
|
8
|
-
Before answering **code-location / architecture / caller-chain / config-schema** questions in this repo, use the retrieval layer deliberately. On Cursor, **`.cursor/rules` is the reliable per-turn policy channel**; the **`beforeSubmitPrompt`** hook (`.cursor/hooks/inject-retrieval-plan.py`) runs **telemetry-only** — it does **not** inject `## 代码库检索计划` blocks. Generate a plan via `route_codebase_retrieval.py --instructions` when needed, or follow the default tool order below. Do **not** depend on end-of-turn retrieval-pack hooks for plans.
|
|
9
|
-
|
|
10
|
-
## Prefer / Adapt / Own (code intelligence)
|
|
11
|
-
|
|
12
|
-
**Three surfaces (do not conflate):** (1) **IDE Editor** — full extension LSP; (2) **Agents Window (Glass)** — staff-reported partial LSP vs Editor ([forum](https://forum.cursor.com/t/cursor-agents-window-lsp-not-working-with-typescript/156772)); (3) **Agent autonomous tools** — [official list](https://cursor.com/docs/agent/overview.md) is search/read/edit/shell/web — **no** `GO_TO_DEFINITION` / raw LSP tool. Trellis routes **Agent tool table** only. See `retrieval-daily-guide.md` § Prefer/Adapt/Own evidence (2026-08-05 smart-search + Native probe).
|
|
13
|
-
|
|
14
|
-
| Need | **Prefer** (Cursor native, Agent-reachable) | **Adapt** (route by intent / `cursorEnv`) | **Own** (codegraph / MCP) |
|
|
15
|
-
| --- | --- | --- | --- |
|
|
16
|
-
| Exact literal / path | **Grep** | — | — |
|
|
17
|
-
| Named-symbol definition (known identifier) | **Grep → Read** | Path hints from semantic when file unknown | codegraph when cross-package trap, overload ambiguity, or blast context needed |
|
|
18
|
-
| Agent-session diagnostics | **ReadLints** (when in tool table) | — | — |
|
|
19
|
-
| Conceptual / how does X work | **Native:** built-in `@codebase` / semantic search (index embeddings; ≠ LSP) | **BYOK:** **fast_context_search** (fast-context MCP). Plans show `cursorEnv`. | — |
|
|
20
|
-
| Caller chain / blast radius | Grep for imports/callbacks (gap-fill) | — | **codegraph_callers** / **codegraph_explore** |
|
|
21
|
-
| Cross-package trap / extension symbol | Grep scoped by package or `extensions/` | — | **codegraph_search** / **codegraph_explore** |
|
|
22
|
-
| Raw LSP / GO_TO_DEFINITION **as Agent tool** | **Not in Agent tool table** (official docs + Native probe 2026-08-05) | IDE Editor has LSP; Agents Window may lack parity — human UI, not Agent routing | codegraph when Grep+Read insufficient |
|
|
23
|
-
|
|
24
|
-
**Rollback:** revert this rule + `retrieval-daily-guide.md` Prefer rows to the pre-P1 codegraph-first definition wording; keep codegraph MCP enabled.
|
|
25
|
-
|
|
26
|
-
## When a retrieval plan block is present
|
|
27
|
-
|
|
28
|
-
If the user message or Trellis context contains a block starting with `## 代码库检索计划` or `## Codebase retrieval plan`:
|
|
29
|
-
|
|
30
|
-
1. Execute steps **in order** before stating file paths or behavior claims.
|
|
31
|
-
2. Treat each step as mandatory tooling (not suggestions).
|
|
32
|
-
3. Finish with **Read** verification on cited sources (definition jumps: **Grep → Read** first; **codegraph** when the plan lists structural/trap routes or Grep is ambiguous).
|
|
33
|
-
|
|
34
|
-
Generate a fresh plan when needed:
|
|
35
|
-
|
|
36
|
-
```powershell
|
|
37
|
-
python ./.cstl/scripts/route_codebase_retrieval.py "<question>" --instructions
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
JSON (includes `agentInstructions`):
|
|
41
|
-
|
|
42
|
-
```powershell
|
|
43
|
-
python ./.cstl/scripts/route_codebase_retrieval.py "<question>" --json
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Default tool order (no plan block)
|
|
47
|
-
|
|
48
|
-
| Need | Tool (Cursor) |
|
|
49
|
-
| --- | --- |
|
|
50
|
-
| Exact string / path | **Grep** (Instant Grep) |
|
|
51
|
-
| Named-symbol definition | **Grep** → **Read** (Prefer native); **codegraph_explore** / **codegraph_search** when trap, overload, or blast context needed |
|
|
52
|
-
| IDE diagnostics | **ReadLints** on touched or cited files |
|
|
53
|
-
| Who calls / blast radius | **codegraph_callers** / **codegraph_explore** → Grep for imports/callbacks |
|
|
54
|
-
| Same name across packages (trap) | **codegraph_search** / **codegraph_explore** → Grep |
|
|
55
|
-
| Extension symbols | **codegraph_search** under `extensions/` |
|
|
56
|
-
| Conceptual / how does X work | **Native:** built-in `@codebase` / semantic search. **BYOK:** **fast_context_search** (fast-context MCP). Plans show `cursorEnv`. |
|
|
57
|
-
| Policy / architecture / boundaries / storage rules | **Grep** on `AGENTS.md`, `**/AGENTS.md`, `.cstl/spec/**`, `README.md` (router `policy-docs-rg`) before implementation modules |
|
|
58
|
-
| Wide cross-cutting explore | **Native:** DEEP_SEARCH or Explore subagent. **BYOK:** **Task explore** subagent, then Grep/codegraph/Read |
|
|
59
|
-
|
|
60
|
-
## Semantic on Cursor (`platform-semantic`)
|
|
61
|
-
|
|
62
|
-
- **cursorEnv native:** built-in codebase semantic search (`platformNative`). Do **not** use fast-context MCP for semantic Primary.
|
|
63
|
-
- **cursorEnv byok:** **fast-context MCP** is **required** for concept retrieval; built-in `@codebase` is not available in the agent tool list.
|
|
64
|
-
- Override detection: `TRELLIS_CURSOR_BYOK=0|1` or `~/.ccursor/routes.json` `byokMode`.
|
|
65
|
-
|
|
66
|
-
## Result-layer ranking (B / E / D)
|
|
67
|
-
|
|
68
|
-
When the plan block includes **结果层排序**, apply it **after** collecting path candidates and **before** stating Top-1 / Top-5: caller concrete sites over assembly files; trap demotion; env scripts/e2e/bench over generic `src/auth`/`paths`. Offline reorder: `rank_retrieval_candidates.py`.
|
|
69
|
-
|
|
70
|
-
## codegraph-only value (Own layer)
|
|
71
|
-
|
|
72
|
-
Use codegraph for **call chains**, **cross-package trap disambiguation**, **extension symbol resolution**, **impact/blast radius**, and **definition/reference when native Grep+Read is ambiguous** — not for pure literal search (Grep), simple single-package definition jump (Grep+Read), BYOK concept Primary (use fast-context), Agent diagnostics (ReadLints), or **replacing IDE Editor LSP** (human surface).
|
|
73
|
-
|
|
74
|
-
**Re-probe gate:** Before elevating raw LSP to Prefer, verify Agent tool table + `retrieval-daily-guide.md` evidence notes; if external docs add LSP tools but Native probe fails, **keep fallback** and document the gap.
|
|
75
|
-
|
|
76
|
-
## External facts
|
|
77
|
-
|
|
78
|
-
Web/current events: **smart-search** first per `.cstl/framework/retrieval-daily-guide.md` (see **External-knowledge gate** for search-or-not).
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# Cursor++ Local Bundle
|
|
2
|
-
|
|
3
|
-
> **Native Cursor users:** safe to ignore or delete this directory unless using **Cursor++ BYOK** on **this repo**.
|
|
4
|
-
|
|
5
|
-
**Coexistence:** Native and BYOK can run on the same machine across different projects. This bundle is **per-repo** (`cstl init --cursor --cursor2plus`); sibling repos may use `cstl init --cursor` only. Full guide: cursor-trellis `docs/cursor.md` — section *Native and BYOK coexistence (not either/or)*.
|
|
6
|
-
|
|
7
|
-
**Who needs this:** Cursor IDE with [Cursor++](https://ccursor.cometix.dev) (BYOK proxy). Method 2.5 patches the Cursor++ task model resolver (historically located via `WPeLc8` in verified builds) so Trellis Task subagents get per-role BYOK slugs instead of inheriting the parent model. **After any Cursor or Cursor++ upgrade**, run `python patch_wpelc8.py --check-compat` before re-applying.
|
|
8
|
-
|
|
9
|
-
## Bundle files
|
|
10
|
-
|
|
11
|
-
| File | Purpose |
|
|
12
|
-
|------|---------|
|
|
13
|
-
| `patch_wpelc8.py` | Operator CLI: dry-run map, compat check, apply (with `--approve`), revert |
|
|
14
|
-
| `smoke.py` | Health smoke: env, patch status, configured roles (no secret reads) |
|
|
15
|
-
| `trellis_task_models_config.py` | JSON5 + providers catalog resolver (used by patch) |
|
|
16
|
-
| `config.local.json.example` | Optional paths (`extensionJs`, `ccursorHome`, …) |
|
|
17
|
-
| `config.local.json` | Your local paths (gitignored; never commit secrets) |
|
|
18
|
-
|
|
19
|
-
User-wide model doc: `~/.ccursor/trellis-task-models.json5` (see `../trellis-task-models.json5.example`). Project override: `../subagent-models.json` (optional).
|
|
20
|
-
|
|
21
|
-
## Compatibility window
|
|
22
|
-
|
|
23
|
-
- **Verified:** Cursor **3.7.27** / Cursor++ **v0.0.11** (see `.cstl/framework/cursor-subagent-policy.md`, 2026-06-18)
|
|
24
|
-
- **Re-verify** after any Cursor or Cursor++ upgrade: `python patch_wpelc8.py --check-compat`
|
|
25
|
-
- If `--check-compat` reports `fail` or `unknown`, treat the patch as stale until you re-apply or revert
|
|
26
|
-
|
|
27
|
-
## Method 2.5 workflow
|
|
28
|
-
|
|
29
|
-
1. **Dry-run map** — `python patch_wpelc8.py --print-map` (no file writes)
|
|
30
|
-
2. **Operator approval** — review map and compat output; decide to proceed
|
|
31
|
-
3. **Apply** — `python patch_wpelc8.py --apply --approve` (writes `extension.js`)
|
|
32
|
-
4. **Reload Cursor** — Developer: Reload Window (once per apply/revert)
|
|
33
|
-
5. **A ≠ B probe** — parent chat model must differ from a patched subagent map target; dispatch a `cstl-*` Task and confirm the subagent self-reports the **map target** slug/model, not the parent
|
|
34
|
-
6. **Revert if needed** — `python patch_wpelc8.py --revert` then Reload Window
|
|
35
|
-
|
|
36
|
-
Agent-led setup: run skill **`cstl-cursor2plus-setup`** in Cursor Agent (lists models, writes JSON5, runs patch steps).
|
|
37
|
-
|
|
38
|
-
## Revert recipe
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
cd .cstl/local/cursor2plus
|
|
42
|
-
python patch_wpelc8.py --revert
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Then **Developer: Reload Window**. Subagents return to **inherit parent** BYOK model. Re-apply only after `--check-compat` is `ok` and you have explicit `--approve`.
|
|
46
|
-
|
|
47
|
-
## A ≠ B verification recipe
|
|
48
|
-
|
|
49
|
-
Goal: prove the patch routes **subagent** model independently of the **parent** session model.
|
|
50
|
-
|
|
51
|
-
1. Set parent chat to model **A** (any BYOK model in Cursor++).
|
|
52
|
-
2. Ensure `trellis-task-models.json5` maps e.g. `cstl-implement` to model **B** (`primary`/`fallback` resolving to a different slug than A).
|
|
53
|
-
3. `python patch_wpelc8.py --print-map` — note the slug for `cstl-implement` (= map target **B**).
|
|
54
|
-
4. `python patch_wpelc8.py --apply --approve` → Reload Window.
|
|
55
|
-
5. Dispatch a `cstl-implement` Task from a parent on model **A**.
|
|
56
|
-
6. **Pass:** subagent self-report / trace shows **B** (map target), not **A**.
|
|
57
|
-
7. **Fail:** subagent shows **A** → patch stale or not applied; run `--check-compat`, re-patch, or `--revert`.
|
|
58
|
-
|
|
59
|
-
## CLI reference
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
python patch_wpelc8.py --print-map # dry-run slug map
|
|
63
|
-
python patch_wpelc8.py --check-compat # WPeLc8 locatability (no writes)
|
|
64
|
-
python patch_wpelc8.py --apply --approve # write patch (requires --approve)
|
|
65
|
-
python patch_wpelc8.py --apply --dry-run # validate without write
|
|
66
|
-
python patch_wpelc8.py --revert # remove patch
|
|
67
|
-
python patch_wpelc8.py --explain # JSON5 key meanings
|
|
68
|
-
python patch_wpelc8.py --list-models # catalog from providers.json
|
|
69
|
-
python smoke.py # env + patch_status smoke
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
`--apply` without `--approve` **refuses** and exits non-zero.
|
|
73
|
-
|
|
74
|
-
## What to put in `trellis-task-models.json5`
|
|
75
|
-
|
|
76
|
-
| JSON key (under `models`) | Meaning |
|
|
77
|
-
|---------------------------|---------|
|
|
78
|
-
| `cstl-research` | Trellis research Task subagent |
|
|
79
|
-
| `cstl-implement` | Trellis implement (+ Parent/Child default Task) |
|
|
80
|
-
| `cstl-check` | Trellis check Task subagent |
|
|
81
|
-
| `generalPurpose` / `shell` / `best-of-n-runner` | Cursor built-in Task types |
|
|
82
|
-
|
|
83
|
-
Each role: `{ "primary": "<name>", "fallback": "<name>" }`. Names: **apiModel** or **displayName** from Cursor++ (`--list-models`). **Explore** is not in this file — use the Cursor++ panel.
|
|
84
|
-
|
|
85
|
-
Policy: `.cstl/framework/cursor-subagent-policy.md` (Method 2.5 / 2.6).
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export declare const cursor2plusPatchScript: string;
|
|
2
|
-
export declare const cursor2plusReadme: string;
|
|
3
|
-
export declare const cursor2plusSmokeScript: string;
|
|
4
|
-
export declare const cursor2plusConfigExample: string;
|
|
5
|
-
export declare const subagentModelsExample: string;
|
|
6
|
-
export declare const trellisTaskModelsJson5Example: string;
|
|
7
|
-
export declare const trellisTaskModelsConfigPy: string;
|
|
8
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/templates/trellis/local/index.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,sBAAsB,QAA+B,CAAC;AACnE,eAAO,MAAM,iBAAiB,QAAyB,CAAC;AACxD,eAAO,MAAM,sBAAsB,QAAwB,CAAC;AAC5D,eAAO,MAAM,wBAAwB,QAAyC,CAAC;AAC/E,eAAO,MAAM,qBAAqB,QAA4C,CAAC;AAC/E,eAAO,MAAM,6BAA6B,QAEzC,CAAC;AACF,eAAO,MAAM,yBAAyB,QAA6C,CAAC"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { dirname, join } from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
5
|
-
function readLocal(name) {
|
|
6
|
-
return readFileSync(join(__dirname, name), "utf-8");
|
|
7
|
-
}
|
|
8
|
-
export const cursor2plusPatchScript = readLocal("patch_wpelc8.py");
|
|
9
|
-
export const cursor2plusReadme = readLocal("README.md");
|
|
10
|
-
export const cursor2plusSmokeScript = readLocal("smoke.py");
|
|
11
|
-
export const cursor2plusConfigExample = readLocal("config.local.json.example");
|
|
12
|
-
export const subagentModelsExample = readLocal("subagent-models.json.example");
|
|
13
|
-
export const trellisTaskModelsJson5Example = readLocal("trellis-task-models.json5.example");
|
|
14
|
-
export const trellisTaskModelsConfigPy = readLocal("trellis_task_models_config.py");
|
|
15
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/templates/trellis/local/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE1D,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,SAAS,CAAC,iBAAiB,CAAC,CAAC;AACnE,MAAM,CAAC,MAAM,iBAAiB,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;AACxD,MAAM,CAAC,MAAM,sBAAsB,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;AAC5D,MAAM,CAAC,MAAM,wBAAwB,GAAG,SAAS,CAAC,2BAA2B,CAAC,CAAC;AAC/E,MAAM,CAAC,MAAM,qBAAqB,GAAG,SAAS,CAAC,8BAA8B,CAAC,CAAC;AAC/E,MAAM,CAAC,MAAM,6BAA6B,GAAG,SAAS,CACpD,mCAAmC,CACpC,CAAC;AACF,MAAM,CAAC,MAAM,yBAAyB,GAAG,SAAS,CAAC,+BAA+B,CAAC,CAAC"}
|
|
@@ -1,421 +0,0 @@
|
|
|
1
|
-
"""Trellis: reversible Cursor++ WPeLc8 subagent model map (BYOK). See README.md."""
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
|
|
4
|
-
import argparse
|
|
5
|
-
import json
|
|
6
|
-
import os
|
|
7
|
-
import sys
|
|
8
|
-
from pathlib import Path
|
|
9
|
-
|
|
10
|
-
from trellis_task_models_config import (
|
|
11
|
-
KNOWN_SUBAGENT_TYPES,
|
|
12
|
-
SUBAGENT_TYPE_HELP,
|
|
13
|
-
extract_raw_slots,
|
|
14
|
-
load_providers_catalog,
|
|
15
|
-
load_task_models_document,
|
|
16
|
-
resolve_slots_to_slugs,
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
MARKER = "/*TRELLIS_B2_WPeLc8*/"
|
|
20
|
-
INJECT_NEEDLE = "});return!UbAQWn||"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def _repo_root(start: Path) -> Path:
|
|
24
|
-
cur = start.resolve()
|
|
25
|
-
for _ in range(12):
|
|
26
|
-
if (cur / ".cstl").is_dir():
|
|
27
|
-
return cur
|
|
28
|
-
if cur.parent == cur:
|
|
29
|
-
break
|
|
30
|
-
cur = cur.parent
|
|
31
|
-
return start.resolve()
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def _merge_slot_maps(*layers: dict[str, list[str]]) -> dict[str, list[str]]:
|
|
35
|
-
merged: dict[str, list[str]] = {}
|
|
36
|
-
for layer in layers:
|
|
37
|
-
for k, v in layer.items():
|
|
38
|
-
merged[k] = list(v)
|
|
39
|
-
return merged
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def _ccursor_home(config: dict) -> Path:
|
|
43
|
-
for key in ("ccursorHome", "ccursor_home"):
|
|
44
|
-
if isinstance(config.get(key), str) and config[key].strip():
|
|
45
|
-
return Path(config[key].strip()).expanduser()
|
|
46
|
-
env = os.environ.get("TRELLIS_CCURSOR_HOME", "").strip()
|
|
47
|
-
if env:
|
|
48
|
-
return Path(env).expanduser()
|
|
49
|
-
return Path.home() / ".ccursor"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def _load_config(bundle_dir: Path) -> dict:
|
|
53
|
-
cfg_path = bundle_dir / "config.local.json"
|
|
54
|
-
if not cfg_path.is_file():
|
|
55
|
-
return {}
|
|
56
|
-
try:
|
|
57
|
-
data = json.loads(cfg_path.read_text(encoding="utf-8"))
|
|
58
|
-
return data if isinstance(data, dict) else {}
|
|
59
|
-
except (OSError, json.JSONDecodeError):
|
|
60
|
-
return {}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def resolve_providers_json(config: dict) -> Path:
|
|
64
|
-
for key in ("providersJson", "providers_json"):
|
|
65
|
-
if isinstance(config.get(key), str) and config[key].strip():
|
|
66
|
-
return Path(config[key].strip()).expanduser()
|
|
67
|
-
env = os.environ.get("TRELLIS_CCURSOR_PROVIDERS", "").strip()
|
|
68
|
-
if env:
|
|
69
|
-
return Path(env).expanduser()
|
|
70
|
-
return _ccursor_home(config) / "providers.json"
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def _first_existing(*paths: Path) -> Path | None:
|
|
74
|
-
for p in paths:
|
|
75
|
-
if p.is_file():
|
|
76
|
-
return p
|
|
77
|
-
return None
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
def resolve_user_models_path(config: dict) -> Path:
|
|
81
|
-
ccursor = _ccursor_home(config)
|
|
82
|
-
if isinstance(config.get("userModelsJson"), str) and config["userModelsJson"].strip():
|
|
83
|
-
return Path(config["userModelsJson"].strip()).expanduser()
|
|
84
|
-
found = _first_existing(
|
|
85
|
-
ccursor / "trellis-task-models.json5",
|
|
86
|
-
ccursor / "trellis-task-models.json",
|
|
87
|
-
)
|
|
88
|
-
return found or (ccursor / "trellis-task-models.json5")
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def resolve_project_models_path(bundle_dir: Path, config: dict) -> Path | None:
|
|
92
|
-
root = _repo_root(bundle_dir)
|
|
93
|
-
if isinstance(config.get("projectModelsJson"), str) and config["projectModelsJson"].strip():
|
|
94
|
-
p = Path(config["projectModelsJson"].strip()).expanduser()
|
|
95
|
-
return p if p.is_file() else None
|
|
96
|
-
return _first_existing(
|
|
97
|
-
root / ".cstl" / "local" / "subagent-models.json5",
|
|
98
|
-
root / ".cstl" / "local" / "subagent-models.json",
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
def resolve_model_layers(bundle_dir: Path, config: dict, providers_path: Path) -> tuple[dict[str, str], list[str]]:
|
|
103
|
-
user_path = resolve_user_models_path(config)
|
|
104
|
-
project_path = resolve_project_models_path(bundle_dir, config)
|
|
105
|
-
user_slots = extract_raw_slots(load_task_models_document(user_path))
|
|
106
|
-
project_slots = (
|
|
107
|
-
extract_raw_slots(load_task_models_document(project_path))
|
|
108
|
-
if project_path
|
|
109
|
-
else {}
|
|
110
|
-
)
|
|
111
|
-
merged = _merge_slot_maps(user_slots, project_slots)
|
|
112
|
-
return resolve_slots_to_slugs(merged, providers_path)
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
def configured_slot_map(bundle_dir: Path, config: dict) -> dict[str, list[str]]:
|
|
116
|
-
"""Non-secret role → [primary, fallback, …] from JSON5 only (no providers.json read)."""
|
|
117
|
-
user_path = resolve_user_models_path(config)
|
|
118
|
-
project_path = resolve_project_models_path(bundle_dir, config)
|
|
119
|
-
user_slots = extract_raw_slots(load_task_models_document(user_path))
|
|
120
|
-
project_slots = (
|
|
121
|
-
extract_raw_slots(load_task_models_document(project_path))
|
|
122
|
-
if project_path
|
|
123
|
-
else {}
|
|
124
|
-
)
|
|
125
|
-
return _merge_slot_maps(user_slots, project_slots)
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
def _extension_candidates(config: dict) -> list[Path]:
|
|
129
|
-
for key in ("extensionJs", "extension_js"):
|
|
130
|
-
if isinstance(config.get(key), str) and config[key].strip():
|
|
131
|
-
return [Path(config[key].strip()).expanduser()]
|
|
132
|
-
env = os.environ.get("TRELLIS_CURSOR2PLUS_EXTENSION", "").strip()
|
|
133
|
-
if env:
|
|
134
|
-
return [Path(env).expanduser()]
|
|
135
|
-
if sys.platform == "win32":
|
|
136
|
-
local = os.environ.get("LOCALAPPDATA", "")
|
|
137
|
-
return [
|
|
138
|
-
Path(local) / "Programs" / "cursor" / "resources" / "app" / "extensions" / "cursor2plus" / "dist" / "extension.js",
|
|
139
|
-
Path(r"D:\cursor\resources\app\extensions\cursor2plus\dist\extension.js"),
|
|
140
|
-
]
|
|
141
|
-
if sys.platform == "darwin":
|
|
142
|
-
return [
|
|
143
|
-
Path("/Applications/Cursor.app/Contents/Resources/app/extensions/cursor2plus/dist/extension.js"),
|
|
144
|
-
]
|
|
145
|
-
return [
|
|
146
|
-
Path.home() / ".local" / "share" / "cursor" / "resources" / "app" / "extensions" / "cursor2plus" / "dist" / "extension.js",
|
|
147
|
-
]
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
def resolve_extension_js(bundle_dir: Path, config: dict) -> Path:
|
|
151
|
-
for c in _extension_candidates(config):
|
|
152
|
-
if c.is_file():
|
|
153
|
-
return c
|
|
154
|
-
raise SystemExit(
|
|
155
|
-
"extension.js not found. Set extensionJs in config.local.json or run --bootstrap"
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
def try_resolve_extension_js(bundle_dir: Path, config: dict) -> Path | None:
|
|
160
|
-
for c in _extension_candidates(config):
|
|
161
|
-
if c.is_file():
|
|
162
|
-
return c
|
|
163
|
-
return None
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
def build_inject_block(model_map: dict[str, str]) -> str:
|
|
167
|
-
if not model_map:
|
|
168
|
-
raise SystemExit(
|
|
169
|
-
"model map empty — use skill cstl-cursor2plus-setup or write "
|
|
170
|
-
"~/.ccursor/trellis-task-models.json5 (see .cstl/local/trellis-task-models.json5.example)"
|
|
171
|
-
)
|
|
172
|
-
pairs = ",".join(f'"{k}":"{v}"' for k, v in sorted(model_map.items()))
|
|
173
|
-
return (
|
|
174
|
-
f"{MARKER}{{const __T={{{pairs}}};const __m=__T[fQ4YPip];"
|
|
175
|
-
"if(__m&&(!UbAQWn||UbAQWn[Vyazt1(gvQ2P56[0x24a3])][Vyazt1(gvQ2P56[0x204e])]"
|
|
176
|
-
"===Vyazt1(gvQ2P56[0x2cda])))return __m;}"
|
|
177
|
-
)
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
def find_wpelc8_body(source: str) -> tuple[int, int]:
|
|
181
|
-
start = source.find("function WPeLc8(")
|
|
182
|
-
if start < 0:
|
|
183
|
-
raise SystemExit("WPeLc8 not found — Cursor++/extension version mismatch?")
|
|
184
|
-
end = source.find("async function*o4ZNpa", start)
|
|
185
|
-
if end < 0:
|
|
186
|
-
raise SystemExit("WPeLc8 end anchor not found")
|
|
187
|
-
return start, end
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
def probe_wpelc8_compat(source: str) -> dict[str, str]:
|
|
191
|
-
"""Non-exiting WPeLc8 / inject-anchor probe for --check-compat and smoke."""
|
|
192
|
-
start = source.find("function WPeLc8(")
|
|
193
|
-
if start < 0:
|
|
194
|
-
return {"wpelc8": "not_locatable", "inject_anchor": "unknown", "end_anchor": "unknown"}
|
|
195
|
-
end = source.find("async function*o4ZNpa", start)
|
|
196
|
-
if end < 0:
|
|
197
|
-
return {"wpelc8": "locatable", "inject_anchor": "unknown", "end_anchor": "missing"}
|
|
198
|
-
fn = source[start:end]
|
|
199
|
-
anchor = "present" if INJECT_NEEDLE in fn else "missing"
|
|
200
|
-
return {"wpelc8": "locatable", "inject_anchor": anchor, "end_anchor": "present"}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
def apply_patch(source: str, inject: str) -> str:
|
|
204
|
-
start, end = find_wpelc8_body(source)
|
|
205
|
-
fn = source[start:end]
|
|
206
|
-
if MARKER in fn:
|
|
207
|
-
fn = remove_patch_from_fn(fn)
|
|
208
|
-
if INJECT_NEEDLE not in fn:
|
|
209
|
-
raise SystemExit(f"inject anchor missing: {INJECT_NEEDLE!r}")
|
|
210
|
-
fn_new = fn.replace(INJECT_NEEDLE, f"}});{inject}return!UbAQWn||", 1)
|
|
211
|
-
return source[:start] + fn_new + source[end:]
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
def remove_patch_from_fn(fn: str) -> str:
|
|
215
|
-
import re
|
|
216
|
-
|
|
217
|
-
return re.sub(
|
|
218
|
-
re.escape(MARKER) + r"\{const __T=\{[^}]+\};const __m=__T\[fQ4YPip\];"
|
|
219
|
-
r"if\(__m&&\(!UbAQWn\|\|UbAQWn\[Vyazt1\(gvQ2P56\[0x24a3\]\)\]\[Vyazt1\(gvQ2P56\[0x204e\]\)\]"
|
|
220
|
-
r"===Vyazt1\(gvQ2P56\[0x2cda\]\)\)\)return __m;\}",
|
|
221
|
-
"",
|
|
222
|
-
fn,
|
|
223
|
-
count=1,
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
def remove_patch(source: str) -> str:
|
|
228
|
-
if MARKER not in source:
|
|
229
|
-
raise SystemExit("marker not found — not patched?")
|
|
230
|
-
start, end = find_wpelc8_body(source)
|
|
231
|
-
fn = remove_patch_from_fn(source[start:end])
|
|
232
|
-
return source[:start] + fn + source[end:]
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
def cmd_explain() -> None:
|
|
236
|
-
print("trellis-task-models.json5 — Agent 协助填写;用户只选模型名")
|
|
237
|
-
print("每项: { primary, fallback } — 首选不可用则自动备选 (WARN)")
|
|
238
|
-
print()
|
|
239
|
-
for key in KNOWN_SUBAGENT_TYPES:
|
|
240
|
-
print(f" {key}")
|
|
241
|
-
print(f" → {SUBAGENT_TYPE_HELP.get(key, '')}")
|
|
242
|
-
print()
|
|
243
|
-
print("Skill: cstl-cursor2plus-setup (init 后与大模型交互完成配置)")
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
def cmd_list_models(providers_path: Path) -> None:
|
|
247
|
-
by_slug, _ = load_providers_catalog(providers_path)
|
|
248
|
-
if not by_slug:
|
|
249
|
-
raise SystemExit(f"no models in {providers_path}")
|
|
250
|
-
print(f"# {providers_path}")
|
|
251
|
-
print("# 给用户选 primary/fallback 时引用 apiModel 或 displayName")
|
|
252
|
-
print()
|
|
253
|
-
rows = sorted(by_slug.values(), key=lambda r: (str(r.get("provider")), str(r.get("displayName"))))
|
|
254
|
-
for r in rows:
|
|
255
|
-
print(
|
|
256
|
-
f" {r.get('displayName')!r:28} apiModel={r.get('apiModel')!r:32} "
|
|
257
|
-
f"slug={r.get('slug')} provider={r.get('provider')}"
|
|
258
|
-
)
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
def cmd_bootstrap(bundle_dir: Path) -> None:
|
|
262
|
-
config = _load_config(bundle_dir)
|
|
263
|
-
cfg_out = bundle_dir / "config.local.json"
|
|
264
|
-
if not cfg_out.is_file():
|
|
265
|
-
config = {}
|
|
266
|
-
try:
|
|
267
|
-
resolve_extension_js(bundle_dir, config)
|
|
268
|
-
print("extension.js auto-detected", file=sys.stderr)
|
|
269
|
-
except SystemExit:
|
|
270
|
-
path = input("Paste full path to cursor2plus/dist/extension.js: ").strip()
|
|
271
|
-
if path:
|
|
272
|
-
config["extensionJs"] = path
|
|
273
|
-
cfg_out.write_text(json.dumps(config, indent=2) + "\n", encoding="utf-8")
|
|
274
|
-
print("wrote", cfg_out)
|
|
275
|
-
print("Next: in Cursor Agent, run skill cstl-cursor2plus-setup", file=sys.stderr)
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
def cmd_check_compat(bundle_dir: Path, config: dict) -> int:
|
|
279
|
-
extension = try_resolve_extension_js(bundle_dir, config)
|
|
280
|
-
result: dict[str, object] = {
|
|
281
|
-
"extension": str(extension) if extension else None,
|
|
282
|
-
"patch_marker_present": False,
|
|
283
|
-
"wpelc8": "unknown",
|
|
284
|
-
"inject_anchor": "unknown",
|
|
285
|
-
"end_anchor": "unknown",
|
|
286
|
-
}
|
|
287
|
-
if extension is None:
|
|
288
|
-
result["status"] = "unknown"
|
|
289
|
-
result["hint"] = (
|
|
290
|
-
"extension.js not found — set extensionJs in config.local.json or run --bootstrap; "
|
|
291
|
-
"manual verification required"
|
|
292
|
-
)
|
|
293
|
-
print(json.dumps(result, indent=2, sort_keys=True))
|
|
294
|
-
return 2
|
|
295
|
-
|
|
296
|
-
source = extension.read_text(encoding="utf-8", errors="ignore")
|
|
297
|
-
result["patch_marker_present"] = MARKER in source
|
|
298
|
-
probe = probe_wpelc8_compat(source)
|
|
299
|
-
result.update(probe)
|
|
300
|
-
|
|
301
|
-
wpelc8 = probe["wpelc8"]
|
|
302
|
-
anchor = probe["inject_anchor"]
|
|
303
|
-
end_anchor = probe.get("end_anchor", "unknown")
|
|
304
|
-
|
|
305
|
-
if wpelc8 == "not_locatable" or anchor == "missing":
|
|
306
|
-
result["status"] = "fail"
|
|
307
|
-
result["hint"] = (
|
|
308
|
-
"WPeLc8 or inject anchor not found after Cursor/Cursor++ upgrade — "
|
|
309
|
-
"re-run patch with --apply --approve or revert to inherit-parent"
|
|
310
|
-
)
|
|
311
|
-
elif wpelc8 == "unknown" or anchor == "unknown" or end_anchor == "unknown":
|
|
312
|
-
result["status"] = "unknown"
|
|
313
|
-
result["hint"] = "Locator uncertain — manually verify extension.js after any upgrade"
|
|
314
|
-
else:
|
|
315
|
-
result["status"] = "ok"
|
|
316
|
-
result["hint"] = "WPeLc8 and inject anchor locatable"
|
|
317
|
-
|
|
318
|
-
print(json.dumps(result, indent=2, sort_keys=True))
|
|
319
|
-
return 0 if result["status"] == "ok" else (1 if result["status"] == "fail" else 2)
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
def main() -> None:
|
|
323
|
-
ap = argparse.ArgumentParser(
|
|
324
|
-
description="Trellis Cursor++ WPeLc8 model map (Method 2.5)",
|
|
325
|
-
epilog=(
|
|
326
|
-
"Read-only: --print-map, --check-compat. "
|
|
327
|
-
"Write: --apply --approve (or --revert). "
|
|
328
|
-
"Never runs in CI by default."
|
|
329
|
-
),
|
|
330
|
-
)
|
|
331
|
-
ap.add_argument("--revert", action="store_true", help="Remove Trellis patch from extension.js")
|
|
332
|
-
ap.add_argument("--apply", action="store_true", help="Apply patch to extension.js")
|
|
333
|
-
ap.add_argument(
|
|
334
|
-
"--approve",
|
|
335
|
-
action="store_true",
|
|
336
|
-
help="Explicit operator approval (required for --apply writes)",
|
|
337
|
-
)
|
|
338
|
-
ap.add_argument(
|
|
339
|
-
"--dry-run",
|
|
340
|
-
action="store_true",
|
|
341
|
-
help="With --apply: validate patch without writing extension.js",
|
|
342
|
-
)
|
|
343
|
-
ap.add_argument("--bootstrap", action="store_true", help="Create config.local.json with extension path")
|
|
344
|
-
ap.add_argument("--explain", action="store_true", help="Explain trellis-task-models.json5 keys")
|
|
345
|
-
ap.add_argument("--list-models", action="store_true", help="List models from providers.json catalog")
|
|
346
|
-
ap.add_argument("--print-map", action="store_true", help="Dry-run: print resolved slug map (no file writes)")
|
|
347
|
-
ap.add_argument(
|
|
348
|
-
"--check-compat",
|
|
349
|
-
action="store_true",
|
|
350
|
-
help="Check WPeLc8 locatability in current extension.js (no file writes)",
|
|
351
|
-
)
|
|
352
|
-
args = ap.parse_args()
|
|
353
|
-
|
|
354
|
-
bundle_dir = Path(__file__).resolve().parent
|
|
355
|
-
if args.explain:
|
|
356
|
-
cmd_explain()
|
|
357
|
-
return
|
|
358
|
-
if args.bootstrap:
|
|
359
|
-
cmd_bootstrap(bundle_dir)
|
|
360
|
-
return
|
|
361
|
-
|
|
362
|
-
config = _load_config(bundle_dir)
|
|
363
|
-
|
|
364
|
-
if args.check_compat:
|
|
365
|
-
raise SystemExit(cmd_check_compat(bundle_dir, config))
|
|
366
|
-
|
|
367
|
-
providers_path = resolve_providers_json(config)
|
|
368
|
-
|
|
369
|
-
if args.list_models:
|
|
370
|
-
cmd_list_models(providers_path)
|
|
371
|
-
return
|
|
372
|
-
|
|
373
|
-
needs_map = args.print_map or args.apply or args.revert
|
|
374
|
-
model_map: dict[str, str] = {}
|
|
375
|
-
notes: list[str] = []
|
|
376
|
-
if needs_map and not args.revert:
|
|
377
|
-
model_map, notes = resolve_model_layers(bundle_dir, config, providers_path)
|
|
378
|
-
if notes:
|
|
379
|
-
print("resolve:", file=sys.stderr)
|
|
380
|
-
for line in notes:
|
|
381
|
-
print(line, file=sys.stderr)
|
|
382
|
-
if any("ERROR" in line for line in notes):
|
|
383
|
-
raise SystemExit(1)
|
|
384
|
-
|
|
385
|
-
if args.print_map:
|
|
386
|
-
print(json.dumps(model_map, indent=2, sort_keys=True))
|
|
387
|
-
return
|
|
388
|
-
|
|
389
|
-
if args.revert:
|
|
390
|
-
extension = resolve_extension_js(bundle_dir, config)
|
|
391
|
-
source = extension.read_text(encoding="utf-8", errors="ignore")
|
|
392
|
-
new = remove_patch(source)
|
|
393
|
-
extension.write_text(new, encoding="utf-8", newline="\n")
|
|
394
|
-
print("wrote", extension)
|
|
395
|
-
return
|
|
396
|
-
|
|
397
|
-
if args.apply:
|
|
398
|
-
if not args.approve and not args.dry_run:
|
|
399
|
-
print(
|
|
400
|
-
"refused: --apply writes extension.js and requires explicit --approve "
|
|
401
|
-
"(use --dry-run to validate without writing)",
|
|
402
|
-
file=sys.stderr,
|
|
403
|
-
)
|
|
404
|
-
raise SystemExit(1)
|
|
405
|
-
extension = resolve_extension_js(bundle_dir, config)
|
|
406
|
-
source = extension.read_text(encoding="utf-8", errors="ignore")
|
|
407
|
-
inject = build_inject_block(model_map)
|
|
408
|
-
new = apply_patch(source, inject)
|
|
409
|
-
if args.dry_run:
|
|
410
|
-
print("ok patch delta", len(new) - len(source))
|
|
411
|
-
return
|
|
412
|
-
extension.write_text(new, encoding="utf-8", newline="\n")
|
|
413
|
-
print("wrote", extension)
|
|
414
|
-
return
|
|
415
|
-
|
|
416
|
-
ap.print_help()
|
|
417
|
-
raise SystemExit(2)
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
if __name__ == "__main__":
|
|
421
|
-
main()
|