Skip to content

Commit 4c3b6ce

Browse files
authored
Merge pull request #117 from asperpharma/copilot/update-cursor-rules-docs
Fix Azure CI failure; add Antigravity feature flag, diagnostic script, and Cursor rules guide
2 parents b1f5417 + 3a24361 commit 4c3b6ce

7 files changed

Lines changed: 286 additions & 16 deletions

File tree

.github/workflows/azure-webapps-node.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ permissions:
3232

3333
jobs:
3434
build:
35+
# Skip this workflow when Azure credentials are not configured.
36+
# To enable Azure deployment, set AZURE_WEBAPP_PUBLISH_PROFILE in
37+
# Settings → Secrets and variables → Actions and update AZURE_WEBAPP_NAME above.
38+
if: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE != '' }}
3539
runs-on: ubuntu-latest
3640
steps:
3741
- uses: actions/checkout@v4
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Copilot & Cursor Rules — Update Guide
2+
3+
This document explains where Cursor rules live, how to create or update them,
4+
and how to keep GitHub Copilot settings in sync.
5+
6+
---
7+
8+
## Where Cursor rules live
9+
10+
All project-specific Cursor rules are stored under **`.cursor/rules/`**.
11+
Each rule is a `.mdc` file (Markdown + metadata front-matter):
12+
13+
```
14+
.cursor/
15+
└── rules/
16+
├── Compliance-Legal-Rules.mdc
17+
├── Monitoring-Quality-Rules.mdc
18+
├── Operational-Workflow-Rules.mdc
19+
└── Strategic-Vision-Rules.mdc
20+
```
21+
22+
Global (user-level) rules live in `~/.cursor/rules/` or are managed via
23+
**Cursor → Settings → Rules for AI**.
24+
25+
---
26+
27+
## Creating or updating rules
28+
29+
Use the built-in **`create-rule`** skill (if available) for scaffolding:
30+
31+
```bash
32+
# Example: scaffold a new rule called "Security-Rules"
33+
cursor skill create-rule Security-Rules
34+
```
35+
36+
To edit an existing rule manually, open the `.mdc` file and update the
37+
front-matter (title, description, `alwaysApply`, `globs`) and the rule body.
38+
39+
---
40+
41+
## Keeping Copilot in sync
42+
43+
When you update a Cursor rule that also affects GitHub Copilot behaviour,
44+
mirror the change in Copilot's instruction settings:
45+
46+
| Setting | Location |
47+
|---|---|
48+
| Review selection instructions | `github.copilot.chat.reviewSelection.instructions` in VS Code / Cursor user settings |
49+
| Commit message instructions | `github.copilot.chat.commitMessageGeneration.instructions` |
50+
| Generate test instructions | `github.copilot.chat.generateTests.instructions` |
51+
52+
The reference file for all custom Copilot/Cursor JSON overrides is
53+
**`cursor-user-settings-FIXED.json`** in the repository root (if present).
54+
Apply it with the `install-cursor` skill or by copying the relevant keys into
55+
your editor's user `settings.json`.
56+
57+
---
58+
59+
## Workflow
60+
61+
1. **Edit rule** — open the relevant `.cursor/rules/*.mdc` file and update.
62+
2. **Sync Copilot** — if the rule change affects code review or generation
63+
instructions, update the corresponding Copilot setting (see table above).
64+
3. **Install settings** — run `install-cursor` skill or apply
65+
`cursor-user-settings-FIXED.json` if prompted.
66+
4. **Commit & push** — rules are committed to the repo so the team shares
67+
the same AI behaviour.
68+
69+
---
70+
71+
## References
72+
73+
- [CURSOR-SETTINGS-FIX](../cursor-user-settings-FIXED.json) *(if present)*
74+
- [.cursorrules](../.cursorrules) — legacy root-level rules file
75+
- [Cursor documentation — Rules for AI](https://cursor.sh/docs/rules-for-ai)
76+
- [GitHub Copilot custom instructions](https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot)

env.main-site.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,9 @@ LOVABLE_WEBHOOK_URL=
4242
SHOPIFY_ADMIN_ACCESS_TOKEN=
4343
SHOPIFY_STORE_DOMAIN=lovable-project-milns.myshopify.com
4444
CSV_PATH=./data/shopify-import-2.csv
45+
46+
# ========== Feature Flags ==========
47+
# Set to "true" to enable Antigravity IDE integration panel and diagnostics.
48+
# Requires the Antigravity language server (language_server_windows_x64.exe) to be running.
49+
# See src/lib/antigravityFeatureFlag.ts and scripts/antigravity-diagnostic.ps1.
50+
VITE_FEATURE_ANTIGRAVITY=false

package-lock.json

Lines changed: 0 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/antigravity-diagnostic.ps1

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Antigravity Language Server Diagnostic Script
2+
# Usage: powershell -NoProfile -ExecutionPolicy Bypass -File "scripts\antigravity-diagnostic.ps1"
3+
#
4+
# Checks whether the Antigravity language server process is running on this machine.
5+
# Mirrors the process check performed by the Antigravity Toolkit VS Code/Cursor extension
6+
# so you can diagnose "no_process" / quota failures without needing the extension UI.
7+
8+
$ProcessName = "language_server_windows_x64"
9+
$FullExe = "$ProcessName.exe"
10+
11+
Write-Host "=== Antigravity Language Server Diagnostic ===" -ForegroundColor Cyan
12+
Write-Host "Searching for process: $FullExe"
13+
Write-Host ""
14+
15+
$processes = Get-Process -Name $ProcessName -ErrorAction SilentlyContinue
16+
17+
if ($processes) {
18+
Write-Host "FOUND: $($processes.Count) instance(s) of $FullExe running." -ForegroundColor Green
19+
$processes | Format-Table Id, Name, CPU, WorkingSet -AutoSize
20+
Write-Host ""
21+
Write-Host "Status: CONNECTED — the Antigravity Toolkit should be able to reach the language server." -ForegroundColor Green
22+
exit 0
23+
} else {
24+
Write-Host "NOT FOUND: no $FullExe process detected." -ForegroundColor Yellow
25+
Write-Host ""
26+
Write-Host "Status: no_process" -ForegroundColor Yellow
27+
Write-Host ""
28+
Write-Host "What this means:" -ForegroundColor Cyan
29+
Write-Host " The Antigravity Toolkit extension connects to an external Antigravity process"
30+
Write-Host " (e.g. Antigravity IDE or its language server). Until that process is running,"
31+
Write-Host " the Toolkit will report 'no_process' and 'Cannot fetch quota: server info not available'."
32+
Write-Host ""
33+
Write-Host "Next steps:" -ForegroundColor Cyan
34+
Write-Host " 1. Start Antigravity IDE (or the app that launches $FullExe)."
35+
Write-Host " 2. Reload Cursor / run this script again to confirm the process is detected."
36+
Write-Host " 3. If you do not use Antigravity, disable or uninstall the 'Toolkit for Antigravity'"
37+
Write-Host " extension in Cursor to stop the repeated connection attempts."
38+
exit 0
39+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { describe, it, expect, vi, afterEach } from "vitest";
2+
3+
/**
4+
* Unit tests for src/lib/antigravityFeatureFlag.ts
5+
*
6+
* Tests the FEATURE_ANTIGRAVITY flag value and the behaviour of
7+
* runAntigravityDiagnostic() under various conditions.
8+
*/
9+
10+
/** Helper type for patching globalThis.window in tests. */
11+
type GlobalWithWindow = typeof globalThis & { window?: unknown };
12+
13+
describe("FEATURE_ANTIGRAVITY flag", () => {
14+
it("defaults to false when VITE_FEATURE_ANTIGRAVITY env var is absent", async () => {
15+
// In the test environment VITE_FEATURE_ANTIGRAVITY is not set,
16+
// so the flag should evaluate to false.
17+
const { FEATURE_ANTIGRAVITY } = await import("../antigravityFeatureFlag");
18+
expect(FEATURE_ANTIGRAVITY).toBe(false);
19+
});
20+
});
21+
22+
describe("runAntigravityDiagnostic()", () => {
23+
afterEach(() => {
24+
vi.unstubAllEnvs();
25+
vi.resetModules();
26+
});
27+
28+
it("returns status 'error' when the feature flag is false", async () => {
29+
const { runAntigravityDiagnostic } = await import("../antigravityFeatureFlag");
30+
const result = await runAntigravityDiagnostic();
31+
expect(result.status).toBe("error");
32+
expect(result.details).toMatch(/disabled by feature flag/i);
33+
});
34+
35+
it("returns status 'error' when called in a browser-like environment (no process on window)", async () => {
36+
// Simulate a browser context: window exists but window.process does not.
37+
const hadWindow = "window" in globalThis;
38+
const originalWindowProcess = (globalThis as GlobalWithWindow & { window?: { process?: unknown } }).window?.process;
39+
40+
// Set up a window object without a .process property
41+
(globalThis as GlobalWithWindow).window = {};
42+
43+
vi.stubEnv("VITE_FEATURE_ANTIGRAVITY", "true");
44+
vi.resetModules();
45+
46+
const { runAntigravityDiagnostic } = await import("../antigravityFeatureFlag");
47+
const result = await runAntigravityDiagnostic();
48+
49+
expect(result.status).toBe("error");
50+
expect(result.details).toMatch(/browser environment/i);
51+
52+
// Restore window
53+
if (hadWindow) {
54+
(globalThis as GlobalWithWindow).window = { process: originalWindowProcess };
55+
} else {
56+
delete (globalThis as GlobalWithWindow).window;
57+
}
58+
});
59+
60+
it("returns status 'error' when flag is true but PowerShell is not available (CI/Linux)", async () => {
61+
// In the Linux CI environment, 'powershell' does not exist.
62+
// The function should catch the exec error and return { status: "error" }.
63+
vi.stubEnv("VITE_FEATURE_ANTIGRAVITY", "true");
64+
vi.resetModules();
65+
66+
const { runAntigravityDiagnostic } = await import("../antigravityFeatureFlag");
67+
const result = await runAntigravityDiagnostic();
68+
69+
// PowerShell is unavailable → exec throws → catch block returns "error"
70+
expect(result.status).toBe("error");
71+
expect(result.details.length).toBeGreaterThan(0);
72+
});
73+
});
74+

src/lib/antigravityFeatureFlag.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/**
2+
* Feature Flag: Antigravity Panel
3+
*
4+
* All Antigravity connection/diagnostic UI or workflow changes must be wrapped
5+
* with this flag, per Operational-Workflow-Rules. This enables safe, incremental
6+
* rollout and easy toggling without redeployment.
7+
*
8+
* Control via environment variable (recommended):
9+
* VITE_FEATURE_ANTIGRAVITY=true — enable
10+
* VITE_FEATURE_ANTIGRAVITY=false — disable (default)
11+
*
12+
* See env.main-site.example and APPLY_TO_MAIN_SITE.md for conventions.
13+
*/
14+
export const FEATURE_ANTIGRAVITY: boolean =
15+
typeof import.meta !== "undefined" &&
16+
import.meta.env &&
17+
typeof import.meta.env.VITE_FEATURE_ANTIGRAVITY !== "undefined"
18+
? String(import.meta.env.VITE_FEATURE_ANTIGRAVITY).toLowerCase() === "true"
19+
: false;
20+
21+
/**
22+
* Run the Antigravity diagnostic PowerShell script and return a structured result.
23+
*
24+
* - Only executes when FEATURE_ANTIGRAVITY is true.
25+
* - Requires a Node.js / Deno-capable runtime (not available in the browser).
26+
* - Runs `scripts/antigravity-diagnostic.ps1` via PowerShell.
27+
* - Returns `{ status, details }` for downstream UI or workflow handling.
28+
* - Follows Monitoring-Quality-Rules: errors produce an escalatable object.
29+
*
30+
* Possible status values:
31+
* "success" — language server process was found.
32+
* "no_process" — script ran but found no language server process.
33+
* "error" — flag disabled, wrong environment, or script failed.
34+
* "escalate" — script output signals uncertainty; human review needed.
35+
*/
36+
export async function runAntigravityDiagnostic(): Promise<{
37+
status: "success" | "no_process" | "error" | "escalate";
38+
details: string;
39+
}> {
40+
if (!FEATURE_ANTIGRAVITY) {
41+
return {
42+
status: "error",
43+
details: "Antigravity diagnostics are disabled by feature flag.",
44+
};
45+
}
46+
47+
// Guard: cannot run PowerShell in a pure browser environment.
48+
if (typeof window !== "undefined" && typeof (window as Window & { process?: unknown }).process === "undefined") {
49+
return {
50+
status: "error",
51+
details: "Cannot run PowerShell diagnostics in browser environment.",
52+
};
53+
}
54+
55+
try {
56+
// Dynamic imports so this module remains safe to bundle in browser contexts
57+
// even though the runtime branch above will never reach here in a browser.
58+
const { exec } = await import("child_process");
59+
const util = await import("util");
60+
const path = await import("path");
61+
const execAsync = util.promisify(exec);
62+
63+
const scriptPath = path.join("scripts", "antigravity-diagnostic.ps1");
64+
const { stdout } = await execAsync(
65+
`powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}"`
66+
);
67+
68+
if (
69+
stdout?.includes("no language_server_windows_x64") ||
70+
stdout?.toLowerCase().includes("no_process")
71+
) {
72+
return { status: "no_process", details: stdout.trim() };
73+
}
74+
75+
return { status: "success", details: stdout?.trim() || "Diagnostic succeeded." };
76+
} catch (err: unknown) {
77+
const e = err as { stderr?: string; message?: string };
78+
const detail = e?.stderr || e?.message || "Unknown error in diagnosis script";
79+
return {
80+
status:
81+
detail.includes("uncertain") || detail.includes("cannot detect")
82+
? "escalate"
83+
: "error",
84+
details: detail,
85+
};
86+
}
87+
}

0 commit comments

Comments
 (0)