fix: match Cursor project slug normalization (#3926)
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
---
|
||||
created: 2026-09-25
|
||||
status: done
|
||||
requirements:
|
||||
- REQ-AGENTS-CURSOR-AUTH-001
|
||||
- REQ-AGENTS-CURSOR-AUTH-003
|
||||
system_design:
|
||||
- ../../specs/agents/system-design/cursor-mcp-oauth-bridge.md
|
||||
legacy_specs: []
|
||||
---
|
||||
|
||||
# Implementation plan: Cursor MCP project slug normalization
|
||||
|
||||
## Overview
|
||||
|
||||
Kandev links shared MCP credentials into a project directory whose name can differ from the directory Cursor Agent CLI opens. The repair updates the shared slug helper and its regression tests in one work order. No profile, launch, or UI contract changes are needed.
|
||||
|
||||
## Root cause and reproduction
|
||||
|
||||
`DeriveCursorProjectSlug` replaces only four punctuation classes and preserves adjacent dashes. For `/Users/cfl12/.kandev/tasks/hello_hj2srhm6/master`, it returns `Users-cfl12--kandev-tasks-hello-hj2srhm6-master`. Cursor's supplied rule replaces every non-ASCII-alphanumeric character with a dash, collapses dash runs, and returns `Users-cfl12-kandev-tasks-hello-hj2srhm6-master`. Kandev writes `mcp-auth.json` under the first directory; Cursor opens the second. The current `TestDeriveCursorProjectSlug` passes because it expects internal dash runs.
|
||||
|
||||
## Scope
|
||||
|
||||
In scope: use Cursor's ASCII-alphanumeric slug rule for project links and current task-root exclusion, preserve exclusion for task directories created with the previous slug rule, and prove the worktree link lands at the expected directory.
|
||||
|
||||
Out of scope: OAuth login, credential aggregation precedence, profile settings, remote executors, migration or deletion of old project directories, and Cursor versions with a different naming rule.
|
||||
|
||||
## Technical approach
|
||||
|
||||
Update `DeriveCursorProjectSlug` in `apps/backend/internal/agent/mcpconfig/cursor_auth_bridge.go` to emit ASCII letters and digits unchanged, emit one dash for each run of other characters, and trim leading and trailing dashes. Keep it pure and retain the empty-slug guard at its callers. Link destinations use the current helper. Task-root exclusion checks both the current root slug and the previous root slug, keeping pre-normalization task project directories out of credential aggregation.
|
||||
|
||||
Update `TestDeriveCursorProjectSlug` in `cursor_auth_bridge_test.go` with literal expected slugs for the task dot-folder example, Unix and Windows paths, punctuation runs, boundary trimming, empty result, and a non-ASCII case. In `TestCursorMCPAuthWorktree`, derive only the randomized temporary root prefix and keep the expected `.kandev/tasks/...` suffix literal.
|
||||
|
||||
## Tests
|
||||
|
||||
| Acceptance criterion | Evidence |
|
||||
| --- | --- |
|
||||
| AC-AGENTS-CURSOR-AUTH-001.1 | `TestCursorMCPAuthWorktree` verifies the linked auth file exists where Cursor's project slug points. |
|
||||
| AC-AGENTS-CURSOR-AUTH-001.4 | `TestDeriveCursorProjectSlug` verifies canonical path spelling, punctuation-run collapse, and Windows forms. |
|
||||
| AC-AGENTS-CURSOR-AUTH-003.1 | Current and legacy configured task-root slugs are excluded from credential aggregation. |
|
||||
|
||||
First run the changed slug and worktree tests against the old helper and confirm the intended failure. Then apply the helper change and run the full work-order commands.
|
||||
|
||||
## Work orders
|
||||
|
||||
- [x] [Task 01: Match Cursor project slugs](task-01-match-cursor-project-slugs.md)
|
||||
|
||||
## Verification results
|
||||
|
||||
The added legacy-root regression failed against the fixup baseline because the regular auth file was aggregated, then passed after exclusion was extended to the previous slug. The full `mcpconfig` race suite, backend lint, backend build, specification catalog validation, spec lint, and `git diff --check` passed. The earlier broad backend test run had four failures outside this work order: two real-process-tree probe assertions and two launcher config-discovery tests selecting `/root/.kandev/config.yaml` instead of temporary configs.
|
||||
|
||||
The regression tests first failed against the old helper with extra dash runs and preserved non-ASCII characters, then passed after normalization changed.
|
||||
|
||||
- `go test -race -v -run 'Test(DeriveCursorProjectSlug|CursorMCPAuthWorktree|AggregateCursorMCPAuthExcludesConfiguredTaskRoot|AggregateCursorMCPAuthAllowsMissingExcludedRoot)$' ./internal/agent/mcpconfig/...` — passed.
|
||||
- `go test -race -v ./internal/agent/mcpconfig/...` — passed.
|
||||
- `go test -race -v ./internal/agent/runtime/lifecycle/...` — passed.
|
||||
- `make -C apps/backend lint test` — lint passed with 0 issues; the full test target reported four unrelated failures. Isolated reruns reproduced `TestProbeRealTree_AllDescendantsPreTurn_Settled`, `TestProbeRealTree_NewDescendantAfterTurnStart_Live`, `TestInstallSystemdDiscoversFlagHomeConfiguration`, and `TestInstallSystemdDiscoversSystemHomeConfiguration`.
|
||||
- `make -C apps/backend build` — passed.
|
||||
|
||||
## Risks
|
||||
|
||||
- Slug collisions and old double-dash project directories remain possible artifacts of Cursor's naming rule. The repair must preserve existing regular auth files and avoid deleting old directories.
|
||||
- Cursor Agent CLI's bundled rule is supplied for this report. A future CLI version could change it; automated tests prove the stated rule, not every released Cursor version.
|
||||
- The broad backend test target had unrelated failures during the original bridge PR; record any repeat failures separately from this repair.
|
||||
@@ -0,0 +1,83 @@
|
||||
---
|
||||
id: "01-match-cursor-project-slugs"
|
||||
title: "Match Cursor project slugs"
|
||||
status: done
|
||||
wave: 1
|
||||
depends_on: []
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-AGENTS-CURSOR-AUTH-001
|
||||
- REQ-AGENTS-CURSOR-AUTH-003
|
||||
acceptance_criteria:
|
||||
- AC-AGENTS-CURSOR-AUTH-001.1
|
||||
- AC-AGENTS-CURSOR-AUTH-001.4
|
||||
- AC-AGENTS-CURSOR-AUTH-003.1
|
||||
system_design:
|
||||
- ../../specs/agents/system-design/cursor-mcp-oauth-bridge.md
|
||||
---
|
||||
|
||||
# Task 01: Match Cursor project slugs
|
||||
|
||||
## Summary
|
||||
|
||||
Make Kandev's Cursor project directory name match the supplied Cursor Agent CLI rule. Prove a task worktree with a `.kandev` path receives its auth link in the directory Cursor opens.
|
||||
|
||||
## In scope
|
||||
|
||||
- Replace the slug helper with ASCII-alphanumeric preservation, dash-run collapse, and boundary trimming.
|
||||
- Update slug table cases and the worktree link assertion, including Unix, Windows drive, Windows network, punctuation, empty, and non-ASCII paths.
|
||||
- Keep task-root exclusion effective for current and pre-normalization project slugs.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Changing credential contents, profile or lifecycle policy, or filesystem cleanup beyond the helper's current callers.
|
||||
|
||||
## Acceptance
|
||||
|
||||
1. `TestDeriveCursorProjectSlug` fails against the old helper for the task dot-folder path and other dash-run cases, then passes with Cursor's expected single-dash names.
|
||||
2. `TestDeriveCursorProjectSlug` supplies literal expected slugs for fixed paths; `TestCursorMCPAuthWorktree` derives only its randomized temporary root prefix, keeps the expected task-path suffix literal, and finds the symlink there.
|
||||
3. Existing bridge and lifecycle tests pass; no regular auth file or source-exclusion safety behavior regresses.
|
||||
4. A regular auth file under a task project directory created with the previous slug rule is excluded from the shared snapshot.
|
||||
|
||||
## Verification
|
||||
|
||||
From the repository root:
|
||||
|
||||
```bash
|
||||
(cd apps/backend && go test -race -v ./internal/agent/mcpconfig/...)
|
||||
(cd apps/backend && go test -race -v ./internal/agent/runtime/lifecycle/...)
|
||||
make -C apps/backend lint test
|
||||
make -C apps/backend build
|
||||
```
|
||||
|
||||
The build command covers the request's separate build check. Record any unrelated broad-suite failure with its failing test and isolate it before reporting the result.
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `apps/backend/internal/agent/mcpconfig/cursor_auth_bridge.go`
|
||||
- `apps/backend/internal/agent/mcpconfig/cursor_auth_bridge_test.go`
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
|
||||
## Risks
|
||||
|
||||
- The directory name is an external Cursor contract; the supplied bundled rule is the compatibility target.
|
||||
- Existing double-dash directories are left in place. Cursor will use the newly named directory on the next eligible launch.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`
|
||||
|
||||
## Inputs
|
||||
|
||||
- `AC-AGENTS-CURSOR-AUTH-001.1`, `.4`, and `AC-AGENTS-CURSOR-AUTH-003.1` in the Cursor bridge requirements.
|
||||
- The helper boundary, task-root exclusion, and file safety sections of the Cursor bridge system design.
|
||||
- The existing `TestDeriveCursorProjectSlug`, `TestCursorMCPAuthWorktree`, and task-root exclusion tests.
|
||||
|
||||
## Results
|
||||
|
||||
Implemented Cursor's ASCII-alphanumeric slug rule with collapsed separators and boundary trimming. Added fixed slug cases for the supplied `.kandev/tasks` path, Windows drive and network paths, punctuation runs, empty output, and non-ASCII characters. The worktree assertion keeps the task-path suffix literal. PR fixup also adds legacy task-root slug exclusion and removes the duplicated current-slug normalizer from tests.
|
||||
|
||||
The slug regression and the added legacy-root regression failed against their respective prior implementations and passed after the fixes. The full `mcpconfig` race suite passed after fixup; the lifecycle race suite had passed during the implementation run. Backend lint passed with 0 issues, `make -C apps/backend build` passed, and specification catalog validation, spec lint, and `git diff --check` passed. The earlier repository-wide backend test run had four isolated failures outside this work order: two real-process-tree probe assertions and two launcher config-discovery tests selecting `/root/.kandev/config.yaml` instead of their temporary configs.
|
||||
@@ -79,3 +79,4 @@ File modification time does not prove credential freshness or token validity.
|
||||
## Implementation plans
|
||||
|
||||
- [Cursor auth bridge plan](../../../plans/cursor-mcp-oauth-bridge/plan.md)
|
||||
- [Cursor slug normalization repair](../../../plans/cursor-mcp-slug-normalization/plan.md)
|
||||
|
||||
@@ -80,8 +80,8 @@ Add `mcpconfig/cursor_auth_bridge.go` with the requested public helpers:
|
||||
- `LinkCursorMCPAuth(workspacePath, cursorHome string, excludedWorkspaceRoots ...string) error`
|
||||
|
||||
Keep slug derivation pure. The link helper resolves an absolute path and evaluates workspace symlinks before derivation.
|
||||
Normalize Windows separators. Replace each slash, dot, underscore, and colon, including a drive-volume separator, with a dash, then trim boundary dashes.
|
||||
Do not collapse internal dash runs. Reject an empty resulting slug.
|
||||
Match Cursor Agent CLI's project-directory normalization: replace each character outside ASCII `A-Z`, `a-z`, and `0-9` with a dash, collapse consecutive dashes, then trim boundary dashes. This covers Unix and Windows separators, punctuation, and non-ASCII characters with the same rule. Reject an empty resulting slug.
|
||||
Use the current slug for link destinations and disabled-link cleanup. Task-root exclusion recognizes both the current slug and the previous normalization so existing task project directories remain excluded after upgrade. Preserve those directories; do not rename or delete them.
|
||||
|
||||
Scan direct project directories under `<cursorHome>/projects`.
|
||||
Exclude the current workspace and project slugs under the default task scratch root and configured task-worktree root, names containing `kandev-tasks`, symlinked project entries, and non-directory entries.
|
||||
@@ -212,7 +212,7 @@ A temporary git repository/worktree test proves the expected link target without
|
||||
|
||||
Desktop and phone Playwright tests prove default-on, save/reload false, re-enable, discard, and absence for other agents.
|
||||
Unit tests cover request omission, migration, duplication, and frontend draft reconciliation.
|
||||
The [plan](../../../plans/cursor-mcp-oauth-bridge/plan.md) owns exact commands and test names.
|
||||
The [original plan](../../../plans/cursor-mcp-oauth-bridge/plan.md) owns the original delivery commands and test names. The [slug normalization repair plan](../../../plans/cursor-mcp-slug-normalization/plan.md) owns the compatibility regression and verification commands.
|
||||
|
||||
Cursor can replace a symlink during its own auth writes. A later enabled launch repairs it only if it remains a symlink.
|
||||
If Cursor creates a regular file, Kandev preserves that file.
|
||||
|
||||
Reference in New Issue
Block a user