vectorforce 0.3.2 → 0.3.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 CHANGED
@@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ---
9
9
 
10
+ ## [0.3.2] - 2026-11-01
11
+
12
+ ### Added
13
+ - **First-Class Support for 4 Additional AI Harnesses**:
14
+ - **Cursor IDE**: Added automated configuration for `.cursor/mcp.json` and `.cursorrules` in `HarnessConfig.installCursor`.
15
+ - **Windsurf (Codeium Cascade)**: Added automated configuration for `.windsurf/mcp_config.json` and `.windsurfrules` in `HarnessConfig.installWindsurf`.
16
+ - **GitHub Copilot / VS Code**: Added automated workspace configuration for `.vscode/mcp.json` and `.github/copilot-instructions.md` in `HarnessConfig.installCopilot`.
17
+ - **Kiro IDE**: Added automated configuration for `.kiro/mcp.json`, `kiro.json`, and `.kiro/rules.md` in `HarnessConfig.installKiro`.
18
+ - **Harness Policy & Tool Schema Expansion**:
19
+ - Updated `APPROVED_DESTINATIONS` in `Authorizer` to approve `cursor`, `windsurf`, `github-copilot`, `copilot`, `kiro`, and `kiro-ide`.
20
+ - Updated MCP tool schemas for `get_resume_briefing`, `export_handoff`, `get_timeline`, and `reason_about_task` to accept all newly supported harnesses.
21
+ - **Universal MCP Configuration Guide in Documentation**:
22
+ - Added dedicated installation instructions to `README.md` for Cline / Roo Code, Zed Editor, JetBrains IDEs (IntelliJ, WebStorm, PyCharm), Sourcegraph Cody, Aider, and generic stdio MCP clients.
23
+ - **Comprehensive Unit & Security Test Coverage**:
24
+ - Added automated reversible install/uninstall tests for Cursor, Windsurf, GitHub Copilot, and Kiro IDE (test suite expanded to 79 tests).
25
+
26
+ ### Changed
27
+ - `vf init`, `vf config install all`, `vf config doctor`, and `vf status` now inspect and provision all 9 AI coding harnesses.
28
+ - Pruned `package.json` package `files` whitelist to strictly include runtime artifacts (`bin/`, `src/`, `studio/dist/`, `CHANGELOG.md`, `LICENSE`, `README.md`).
29
+
30
+ ---
31
+
10
32
  ## [0.2.0] - 2026-10-31
11
33
 
12
34
  ### Added
package/README.md CHANGED
@@ -137,7 +137,7 @@ node bin/vf.js studio
137
137
 
138
138
  ## Model Context Protocol (MCP)
139
139
 
140
- VectorForce exposes a standard stdio JSON-RPC MCP server for direct integration into **Google Antigravity**, **Claude Code**, **Command Code**, **Meta Muse**, and **OpenAI Codex**.
140
+ VectorForce exposes a standard stdio JSON-RPC MCP server for direct integration into **Google Antigravity**, **Claude Code**, **Command Code**, **Meta Muse**, **OpenAI Codex**, **Cursor**, **Windsurf**, **GitHub Copilot**, and **Kiro IDE**.
141
141
 
142
142
  > **How MCP Starts:** You **never** need to run `vf mcp` manually in a terminal. Each AI coding agent reads its configuration file below and automatically spawns VectorForce in the background over `stdio`.
143
143
 
@@ -148,17 +148,21 @@ VectorForce exposes a standard stdio JSON-RPC MCP server for direct integration
148
148
  | **Command Code (`cmd`)** | `.mcp.json` & `commandcode.json` | `node bin/vf.js config install command-code` |
149
149
  | **Meta Muse (`muse`)** | `.muse/mcp_config.json` & `~/.config/muse/settings.json` | `node bin/vf.js config install muse` |
150
150
  | **OpenAI Codex (`codex`)** | `.codex/config.toml` & `~/.codex/config.toml` | `node bin/vf.js config install codex` |
151
+ | **Cursor IDE** | `.cursor/mcp.json` & `.cursorrules` | `node bin/vf.js config install cursor` |
152
+ | **Windsurf (Codeium)** | `.windsurf/mcp_config.json` & `.windsurfrules` | `node bin/vf.js config install windsurf` |
153
+ | **GitHub Copilot / VS Code** | `.vscode/mcp.json` & `.github/copilot-instructions.md` | `node bin/vf.js config install copilot` |
154
+ | **Kiro IDE** | `.kiro/mcp.json` & `kiro.json` | `node bin/vf.js config install kiro` |
151
155
 
152
156
  ### Automated Configuration & Health Check
153
157
  ```bash
154
- # Auto-configure all supported AI harnesses at once:
158
+ # Auto-configure all 9 supported AI harnesses at once:
155
159
  node bin/vf.js config install all
156
160
 
157
161
  # Verify SQLite DB, AGENTS.md, and all MCP client configs:
158
162
  node bin/vf.js status
159
163
  ```
160
164
 
161
- ### JSON Configuration (Antigravity, Claude Code, Command Code, Muse)
165
+ ### JSON Configuration (Antigravity, Claude Code, Command Code, Muse, Cursor, Windsurf, VS Code, Kiro)
162
166
  ```json
163
167
  {
164
168
  "mcpServers": {
@@ -179,6 +183,96 @@ args = ["/absolute/path/to/VectorForce/bin/vf.js", "mcp"]
179
183
  VF_HARNESS = "codex"
180
184
  ```
181
185
 
186
+ ---
187
+
188
+ ## How to Configure & Update MCP for Any Other AI Coding Harness
189
+
190
+ If your AI assistant or IDE is not in the auto-configured list above, you can connect it to VectorForce in seconds using standard MCP configuration:
191
+
192
+ ### 1. Cline & Roo Code (VS Code Extension)
193
+ Open VS Code Settings or click the **MCP** icon in the Cline panel:
194
+ - Open `cline_mcp_settings.json` (or `roo-cline_mcp_settings.json`) located at:
195
+ - **macOS:** `~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json`
196
+ - **Linux:** `~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json`
197
+ - **Windows:** `%APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json`
198
+ - Add the VectorForce entry:
199
+ ```json
200
+ {
201
+ "mcpServers": {
202
+ "vectorforce": {
203
+ "command": "npx",
204
+ "args": ["-y", "vectorforce", "mcp"],
205
+ "disabled": false,
206
+ "autoApprove": [
207
+ "list_tasks",
208
+ "check_workspace_drift",
209
+ "get_resume_briefing",
210
+ "save_checkpoint",
211
+ "reason_about_task"
212
+ ]
213
+ }
214
+ }
215
+ }
216
+ ```
217
+
218
+ ### 2. Zed Editor
219
+ Zed natively supports MCP context servers. Open your Zed configuration (`~/.config/zed/settings.json` or `cmd-,`):
220
+ ```json
221
+ {
222
+ "context_servers": {
223
+ "vectorforce": {
224
+ "command": {
225
+ "path": "npx",
226
+ "args": ["-y", "vectorforce", "mcp"]
227
+ }
228
+ }
229
+ }
230
+ }
231
+ ```
232
+
233
+ ### 3. JetBrains IDEs (IntelliJ IDEA, WebStorm, PyCharm, RustRover)
234
+ For JetBrains IDEs supporting MCP or AI Assistant:
235
+ 1. Open **Settings / Preferences** (`Ctrl+Alt+S` or `Cmd+,`).
236
+ 2. Search for **Model Context Protocol** or **AI Assistant → Context Providers**.
237
+ 3. Click **Add Stdio Server**:
238
+ - **Name:** `vectorforce`
239
+ - **Command:** `node` (or `npx`)
240
+ - **Arguments:** `/path/to/VectorForce/bin/vf.js mcp` (or `-y vectorforce mcp`)
241
+ - **Environment Variables:** `VF_HARNESS=jetbrains`
242
+
243
+ ### 4. Sourcegraph Cody
244
+ In Sourcegraph Cody settings (`cody.experimental.mcp.servers` in VS Code or JetBrains):
245
+ ```json
246
+ {
247
+ "cody.experimental.mcp.servers": {
248
+ "vectorforce": {
249
+ "command": "node",
250
+ "args": ["/path/to/VectorForce/bin/vf.js", "mcp"]
251
+ }
252
+ }
253
+ }
254
+ ```
255
+
256
+ ### 5. Aider (`aider-chat`)
257
+ Aider integrates directly with Git and can ingest VectorForce's immutable architectural briefings:
258
+ ```bash
259
+ # Pipe VectorForce briefing directly to Aider on session start:
260
+ node bin/vf.js resume --task <task_id> --dest cli --raw | aider
261
+
262
+ # Or generate project conventions before running aider:
263
+ node bin/vf.js resume --task <task_id> --dest cli --raw > CONVENTIONS.md
264
+ aider
265
+ ```
266
+
267
+ ### 6. Generic MCP Client (Any Tool Speaking JSON-RPC 2.0 over Stdio)
268
+ For any agent running locally, pass:
269
+ - **Executable:** `node`
270
+ - **Arguments:** `["/path/to/bin/vf.js", "mcp"]`
271
+ - **Working Directory:** Path to your project workspace
272
+ - **Environment:** `VF_WORKSPACE=/path/to/project` (optional if working directory matches)
273
+
274
+ Whenever you update VectorForce (`npm update -g vectorforce`), simply restart your AI agent or IDE window to immediately use the latest MCP tools.
275
+
182
276
  ### Available MCP Tools
183
277
  | Tool | Purpose |
184
278
  |---|---|
package/bin/vf.js CHANGED
@@ -334,11 +334,15 @@ async function main() {
334
334
  HarnessConfig.installCommandCode(cwd);
335
335
  HarnessConfig.installMuseCode(cwd);
336
336
  HarnessConfig.installCodex(cwd);
337
+ HarnessConfig.installCursor(cwd);
338
+ HarnessConfig.installWindsurf(cwd);
339
+ HarnessConfig.installCopilot(cwd);
340
+ HarnessConfig.installKiro(cwd);
337
341
  const agentsMdPath = join(cwd, 'AGENTS.md');
338
342
  if (!existsSync(agentsMdPath)) {
339
343
  writeFileSync(
340
344
  agentsMdPath,
341
- `# Agent Continuity Protocol — ${project.name}\n\nThis repository uses **VectorForce** ("Git for AI Context") across Google Antigravity, Meta Muse, Claude Code, Command Code, and OpenAI Codex.\n\n## Workflow\n1. **Start/Resume Task**: Run \`vf tasks active\`, \`vf drift --task <id>\`, and \`vf resume --task <id> --dest <harness>\` (or MCP tools \`list_tasks\`, \`check_workspace_drift\`, \`get_resume_briefing\`, \`reason_about_task\`).\n2. **Save Checkpoint Before Switching IDE**: Run \`vf checkpoint --task <id> --summary "<summary>" --goal "<goal>" --constraint "<constraint>" --decision "<ID>:<Title>:<Rationale>" --next "<next>" --doc "AGENTS.md"\` (or MCP tool \`save_checkpoint\`).\n`,
345
+ `# Agent Continuity Protocol — ${project.name}\n\nThis repository uses **VectorForce** ("Git for AI Context") across Google Antigravity, Meta Muse, Claude Code, Command Code, OpenAI Codex, Cursor, Windsurf, GitHub Copilot, and Kiro IDE.\n\n## Workflow\n1. **Start/Resume Task**: Run \`vf tasks active\`, \`vf drift --task <id>\`, and \`vf resume --task <id> --dest <harness>\` (or MCP tools \`list_tasks\`, \`check_workspace_drift\`, \`get_resume_briefing\`, \`reason_about_task\`).\n2. **Save Checkpoint Before Switching IDE**: Run \`vf checkpoint --task <id> --summary "<summary>" --goal "<goal>" --constraint "<constraint>" --decision "<ID>:<Title>:<Rationale>" --next "<next>" --doc "AGENTS.md"\` (or MCP tool \`save_checkpoint\`).\n`,
342
346
  'utf8'
343
347
  );
344
348
  }
@@ -582,6 +586,22 @@ async function main() {
582
586
  const p = HarnessConfig.installCodex(cwd);
583
587
  installed.push(`Codex -> ${p} (+ ~/.codex/config.toml)`);
584
588
  }
589
+ if (target === 'cursor' || target === 'all') {
590
+ const p = HarnessConfig.installCursor(cwd);
591
+ installed.push(`Cursor -> ${p} (+ .cursorrules)`);
592
+ }
593
+ if (target === 'windsurf' || target === 'all') {
594
+ const p = HarnessConfig.installWindsurf(cwd);
595
+ installed.push(`Windsurf -> ${p} (+ .windsurfrules)`);
596
+ }
597
+ if (target === 'copilot' || target === 'github-copilot' || target === 'vscode' || target === 'all') {
598
+ const p = HarnessConfig.installCopilot(cwd);
599
+ installed.push(`GitHub Copilot / VS Code -> ${p} (+ .github/copilot-instructions.md)`);
600
+ }
601
+ if (target === 'kiro' || target === 'kiro-ide' || target === 'all') {
602
+ const p = HarnessConfig.installKiro(cwd);
603
+ installed.push(`Kiro IDE -> ${p} (+ kiro.json)`);
604
+ }
585
605
  console.log(`\n✔ Configured harness integration(s):\n - ${installed.join('\n - ')}`);
586
606
  console.log(`\n💡 Next step: Restart or reload your AI agent, then ask in chat:\n "List active VectorForce tasks and check workspace drift"`);
587
607
  break;
@@ -594,7 +614,11 @@ async function main() {
594
614
  { name: 'Google Antigravity (.agents/mcp_config.json)', ok: existsSync(join(cwd, '.agents', 'mcp_config.json')), path: join(cwd, '.agents', 'mcp_config.json') },
595
615
  { name: 'Claude Code & Command Code (.mcp.json)', ok: existsSync(join(cwd, '.mcp.json')), path: join(cwd, '.mcp.json') },
596
616
  { name: 'Meta Muse (.muse/mcp_config.json)', ok: existsSync(join(cwd, '.muse', 'mcp_config.json')), path: join(cwd, '.muse', 'mcp_config.json') },
597
- { name: 'OpenAI Codex (.codex/config.toml)', ok: existsSync(join(cwd, '.codex', 'config.toml')), path: join(cwd, '.codex', 'config.toml') }
617
+ { name: 'OpenAI Codex (.codex/config.toml)', ok: existsSync(join(cwd, '.codex', 'config.toml')), path: join(cwd, '.codex', 'config.toml') },
618
+ { name: 'Cursor (.cursor/mcp.json)', ok: existsSync(join(cwd, '.cursor', 'mcp.json')), path: join(cwd, '.cursor', 'mcp.json') },
619
+ { name: 'Windsurf (.windsurf/mcp_config.json)', ok: existsSync(join(cwd, '.windsurf', 'mcp_config.json')), path: join(cwd, '.windsurf', 'mcp_config.json') },
620
+ { name: 'GitHub Copilot / VS Code (.vscode/mcp.json)', ok: existsSync(join(cwd, '.vscode', 'mcp.json')), path: join(cwd, '.vscode', 'mcp.json') },
621
+ { name: 'Kiro IDE (.kiro/mcp.json)', ok: existsSync(join(cwd, '.kiro', 'mcp.json')), path: join(cwd, '.kiro', 'mcp.json') }
598
622
  ];
599
623
  console.log(`\nVectorForce Workspace & MCP Health Check (${cwd}):\n`);
600
624
  for (const c of checks) {
@@ -621,6 +645,18 @@ async function main() {
621
645
  if (target === 'codex' || target === 'all') {
622
646
  if (HarnessConfig.uninstallCodex(cwd)) uninstalled.push('Codex');
623
647
  }
648
+ if (target === 'cursor' || target === 'all') {
649
+ if (HarnessConfig.uninstallCursor(cwd)) uninstalled.push('Cursor');
650
+ }
651
+ if (target === 'windsurf' || target === 'all') {
652
+ if (HarnessConfig.uninstallWindsurf(cwd)) uninstalled.push('Windsurf');
653
+ }
654
+ if (target === 'copilot' || target === 'github-copilot' || target === 'vscode' || target === 'all') {
655
+ if (HarnessConfig.uninstallCopilot(cwd)) uninstalled.push('GitHub Copilot / VS Code');
656
+ }
657
+ if (target === 'kiro' || target === 'kiro-ide' || target === 'all') {
658
+ if (HarnessConfig.uninstallKiro(cwd)) uninstalled.push('Kiro IDE');
659
+ }
624
660
  console.log(`\n✔ Removed harness integration(s): ${uninstalled.length ? uninstalled.join(', ') : 'none found'}`);
625
661
  break;
626
662
  }
@@ -1101,7 +1137,11 @@ VectorForce Harness Configuration:
1101
1137
  { name: 'Google Antigravity (.agents/mcp_config.json)', ok: existsSync(join(cwd, '.agents', 'mcp_config.json')) },
1102
1138
  { name: 'Claude Code & Command Code (.mcp.json)', ok: existsSync(join(cwd, '.mcp.json')) },
1103
1139
  { name: 'Meta Muse (.muse/mcp_config.json or musecode.json)', ok: existsSync(join(cwd, '.muse', 'mcp_config.json')) || existsSync(join(cwd, 'musecode.json')) },
1104
- { name: 'OpenAI Codex (.codex/config.toml)', ok: existsSync(join(cwd, '.codex', 'config.toml')) }
1140
+ { name: 'OpenAI Codex (.codex/config.toml)', ok: existsSync(join(cwd, '.codex', 'config.toml')) },
1141
+ { name: 'Cursor (.cursor/mcp.json)', ok: existsSync(join(cwd, '.cursor', 'mcp.json')) },
1142
+ { name: 'Windsurf (.windsurf/mcp_config.json)', ok: existsSync(join(cwd, '.windsurf', 'mcp_config.json')) },
1143
+ { name: 'GitHub Copilot / VS Code (.vscode/mcp.json)', ok: existsSync(join(cwd, '.vscode', 'mcp.json')) },
1144
+ { name: 'Kiro IDE (.kiro/mcp.json)', ok: existsSync(join(cwd, '.kiro', 'mcp.json')) }
1105
1145
  ];
1106
1146
  console.log(`\nVectorForce Workspace & MCP Status (${cwd}):\n`);
1107
1147
  for (const c of checks) {
@@ -1109,7 +1149,7 @@ VectorForce Harness Configuration:
1109
1149
  }
1110
1150
  console.log(`\n💡 How it works:`);
1111
1151
  console.log(` 1. You do NOT need to run "vf mcp" manually.`);
1112
- console.log(` 2. Your AI agent (Antigravity, Claude Code, Command Code, Muse, Codex) reads its config file above and automatically spawns "vf mcp" over stdio.`);
1152
+ console.log(` 2. Your AI agent (Antigravity, Claude Code, Command Code, Muse, Codex, Cursor, Windsurf, Copilot, Kiro) reads its config file above and automatically spawns "vf mcp" over stdio.`);
1113
1153
  console.log(` 3. To verify in your AI chat, ask: "List active VectorForce tasks and check workspace drift"\n`);
1114
1154
  break;
1115
1155
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vectorforce",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Portable engineering context platform - Git for AI context",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -543,4 +543,478 @@ export class HarnessConfig {
543
543
 
544
544
  return removed;
545
545
  }
546
+
547
+ // ==========================================
548
+ // Cursor IDE Integration
549
+ // ==========================================
550
+
551
+ /**
552
+ * Generate configuration object for Cursor (.cursor/mcp.json).
553
+ */
554
+ static getCursorServerEntry() {
555
+ return {
556
+ command: 'node',
557
+ args: [HarnessConfig.getBinPath(), 'mcp'],
558
+ env: {
559
+ VF_HARNESS: 'cursor'
560
+ }
561
+ };
562
+ }
563
+
564
+ /**
565
+ * Preview changes to Cursor configuration.
566
+ * @param {string} workspacePath
567
+ */
568
+ static previewCursor(workspacePath) {
569
+ const dir = join(workspacePath, '.cursor');
570
+ const filePath = join(dir, 'mcp.json');
571
+ let current = null;
572
+ if (existsSync(filePath)) {
573
+ try {
574
+ current = JSON.parse(readFileSync(filePath, 'utf8'));
575
+ } catch {
576
+ current = {};
577
+ }
578
+ }
579
+ const mergedContent = {
580
+ ...(current || {}),
581
+ mcpServers: {
582
+ ...(current?.mcpServers || {}),
583
+ vectorforce: HarnessConfig.getCursorServerEntry()
584
+ }
585
+ };
586
+ return {
587
+ filePath,
588
+ exists: existsSync(filePath),
589
+ currentContent: current,
590
+ mergedContent
591
+ };
592
+ }
593
+
594
+ /**
595
+ * Install Cursor MCP configuration and rules reversibly.
596
+ * @param {string} workspacePath
597
+ * @returns {string} filePath
598
+ */
599
+ static installCursor(workspacePath) {
600
+ const { filePath, mergedContent } = HarnessConfig.previewCursor(workspacePath);
601
+ const dir = join(workspacePath, '.cursor');
602
+ if (!existsSync(dir)) {
603
+ mkdirSync(dir, { recursive: true, mode: 0o755 });
604
+ }
605
+ writeFileSync(filePath, JSON.stringify(mergedContent, null, 2) + '\n', 'utf8');
606
+
607
+ // Create .cursorrules if missing
608
+ const cursorRulesPath = join(workspacePath, '.cursorrules');
609
+ if (!existsSync(cursorRulesPath)) {
610
+ writeFileSync(
611
+ cursorRulesPath,
612
+ `# VectorForce Agent Protocol (Cursor)\n\nThis workspace uses VectorForce for architectural continuity and drift verification.\n- Check active tasks & drift: Use MCP tools 'list_tasks' & 'check_workspace_drift'\n- Retrieve briefing: Use MCP tool 'get_resume_briefing'\n- Save checkpoint: Use MCP tool 'save_checkpoint'\n`,
613
+ 'utf8'
614
+ );
615
+ }
616
+
617
+ if (!isTempWorkspace(workspacePath)) {
618
+ try {
619
+ const globalCursorDir = join(homedir(), '.cursor');
620
+ if (existsSync(globalCursorDir)) {
621
+ const globalMcpPath = join(globalCursorDir, 'mcp.json');
622
+ let globalConfig = {};
623
+ if (existsSync(globalMcpPath)) {
624
+ try {
625
+ globalConfig = JSON.parse(readFileSync(globalMcpPath, 'utf8'));
626
+ } catch {
627
+ globalConfig = {};
628
+ }
629
+ }
630
+ globalConfig.mcpServers = {
631
+ ...(globalConfig.mcpServers || {}),
632
+ vectorforce: {
633
+ command: 'node',
634
+ args: [HarnessConfig.getBinPath(), 'mcp', '--workspace', workspacePath],
635
+ env: {
636
+ VF_WORKSPACE: workspacePath,
637
+ VF_HARNESS: 'cursor'
638
+ }
639
+ }
640
+ };
641
+ writeFileSync(globalMcpPath, JSON.stringify(globalConfig, null, 2) + '\n', 'utf8');
642
+ }
643
+ } catch {}
644
+ }
645
+
646
+ return filePath;
647
+ }
648
+
649
+ /**
650
+ * Reversibly uninstall VectorForce from Cursor configuration.
651
+ * @param {string} workspacePath
652
+ * @returns {boolean} whether removed
653
+ */
654
+ static uninstallCursor(workspacePath) {
655
+ const filePath = join(workspacePath, '.cursor', 'mcp.json');
656
+ let removed = false;
657
+ if (existsSync(filePath)) {
658
+ try {
659
+ const config = JSON.parse(readFileSync(filePath, 'utf8'));
660
+ if (config?.mcpServers?.vectorforce) {
661
+ delete config.mcpServers.vectorforce;
662
+ writeFileSync(filePath, JSON.stringify(config, null, 2) + '\n', 'utf8');
663
+ removed = true;
664
+ }
665
+ } catch {}
666
+ }
667
+ return removed;
668
+ }
669
+
670
+ // ==========================================
671
+ // Windsurf Cascade Integration
672
+ // ==========================================
673
+
674
+ /**
675
+ * Generate configuration object for Windsurf (.windsurf/mcp_config.json).
676
+ */
677
+ static getWindsurfServerEntry() {
678
+ return {
679
+ command: 'node',
680
+ args: [HarnessConfig.getBinPath(), 'mcp'],
681
+ env: {
682
+ VF_HARNESS: 'windsurf'
683
+ }
684
+ };
685
+ }
686
+
687
+ /**
688
+ * Preview changes to Windsurf configuration.
689
+ * @param {string} workspacePath
690
+ */
691
+ static previewWindsurf(workspacePath) {
692
+ const dir = join(workspacePath, '.windsurf');
693
+ const filePath = join(dir, 'mcp_config.json');
694
+ let current = null;
695
+ if (existsSync(filePath)) {
696
+ try {
697
+ current = JSON.parse(readFileSync(filePath, 'utf8'));
698
+ } catch {
699
+ current = {};
700
+ }
701
+ }
702
+ const mergedContent = {
703
+ ...(current || {}),
704
+ mcpServers: {
705
+ ...(current?.mcpServers || {}),
706
+ vectorforce: HarnessConfig.getWindsurfServerEntry()
707
+ }
708
+ };
709
+ return {
710
+ filePath,
711
+ exists: existsSync(filePath),
712
+ currentContent: current,
713
+ mergedContent
714
+ };
715
+ }
716
+
717
+ /**
718
+ * Install Windsurf MCP configuration and rules reversibly.
719
+ * @param {string} workspacePath
720
+ * @returns {string} filePath
721
+ */
722
+ static installWindsurf(workspacePath) {
723
+ const { filePath, mergedContent } = HarnessConfig.previewWindsurf(workspacePath);
724
+ const dir = join(workspacePath, '.windsurf');
725
+ if (!existsSync(dir)) {
726
+ mkdirSync(dir, { recursive: true, mode: 0o755 });
727
+ }
728
+ writeFileSync(filePath, JSON.stringify(mergedContent, null, 2) + '\n', 'utf8');
729
+
730
+ // Create .windsurfrules if missing
731
+ const windsurfRulesPath = join(workspacePath, '.windsurfrules');
732
+ if (!existsSync(windsurfRulesPath)) {
733
+ writeFileSync(
734
+ windsurfRulesPath,
735
+ `# VectorForce Agent Protocol (Windsurf Cascade)\n\nThis workspace uses VectorForce for architectural continuity and drift verification.\n- Check tasks & drift: Call MCP tools 'list_tasks' and 'check_workspace_drift'\n- Resume briefing: Call MCP tool 'get_resume_briefing'\n- Save checkpoint: Call MCP tool 'save_checkpoint'\n`,
736
+ 'utf8'
737
+ );
738
+ }
739
+
740
+ if (!isTempWorkspace(workspacePath)) {
741
+ try {
742
+ const globalWindsurfDir = join(homedir(), '.codeium', 'windsurf');
743
+ if (existsSync(globalWindsurfDir)) {
744
+ const globalMcpPath = join(globalWindsurfDir, 'mcp_config.json');
745
+ let globalConfig = {};
746
+ if (existsSync(globalMcpPath)) {
747
+ try {
748
+ globalConfig = JSON.parse(readFileSync(globalMcpPath, 'utf8'));
749
+ } catch {
750
+ globalConfig = {};
751
+ }
752
+ }
753
+ globalConfig.mcpServers = {
754
+ ...(globalConfig.mcpServers || {}),
755
+ vectorforce: {
756
+ command: 'node',
757
+ args: [HarnessConfig.getBinPath(), 'mcp', '--workspace', workspacePath],
758
+ env: {
759
+ VF_WORKSPACE: workspacePath,
760
+ VF_HARNESS: 'windsurf'
761
+ }
762
+ }
763
+ };
764
+ writeFileSync(globalMcpPath, JSON.stringify(globalConfig, null, 2) + '\n', 'utf8');
765
+ }
766
+ } catch {}
767
+ }
768
+
769
+ return filePath;
770
+ }
771
+
772
+ /**
773
+ * Reversibly uninstall VectorForce from Windsurf configuration.
774
+ * @param {string} workspacePath
775
+ * @returns {boolean} whether removed
776
+ */
777
+ static uninstallWindsurf(workspacePath) {
778
+ const filePath = join(workspacePath, '.windsurf', 'mcp_config.json');
779
+ let removed = false;
780
+ if (existsSync(filePath)) {
781
+ try {
782
+ const config = JSON.parse(readFileSync(filePath, 'utf8'));
783
+ if (config?.mcpServers?.vectorforce) {
784
+ delete config.mcpServers.vectorforce;
785
+ writeFileSync(filePath, JSON.stringify(config, null, 2) + '\n', 'utf8');
786
+ removed = true;
787
+ }
788
+ } catch {}
789
+ }
790
+ return removed;
791
+ }
792
+
793
+ // ==========================================
794
+ // GitHub Copilot & VS Code Integration
795
+ // ==========================================
796
+
797
+ /**
798
+ * Generate configuration object for VS Code / GitHub Copilot (.vscode/mcp.json).
799
+ */
800
+ static getCopilotServerEntry() {
801
+ return {
802
+ command: 'node',
803
+ args: [HarnessConfig.getBinPath(), 'mcp'],
804
+ env: {
805
+ VF_HARNESS: 'copilot'
806
+ }
807
+ };
808
+ }
809
+
810
+ /**
811
+ * Preview changes to Copilot / VS Code configuration.
812
+ * @param {string} workspacePath
813
+ */
814
+ static previewCopilot(workspacePath) {
815
+ const dir = join(workspacePath, '.vscode');
816
+ const filePath = join(dir, 'mcp.json');
817
+ let current = null;
818
+ if (existsSync(filePath)) {
819
+ try {
820
+ current = JSON.parse(readFileSync(filePath, 'utf8'));
821
+ } catch {
822
+ current = {};
823
+ }
824
+ }
825
+ const mergedContent = {
826
+ ...(current || {}),
827
+ mcpServers: {
828
+ ...(current?.mcpServers || {}),
829
+ vectorforce: HarnessConfig.getCopilotServerEntry()
830
+ }
831
+ };
832
+ return {
833
+ filePath,
834
+ exists: existsSync(filePath),
835
+ currentContent: current,
836
+ mergedContent
837
+ };
838
+ }
839
+
840
+ /**
841
+ * Install GitHub Copilot workspace instructions & VS Code MCP configuration.
842
+ * @param {string} workspacePath
843
+ * @returns {string} filePath
844
+ */
845
+ static installCopilot(workspacePath) {
846
+ const { filePath, mergedContent } = HarnessConfig.previewCopilot(workspacePath);
847
+ const vscodeDir = join(workspacePath, '.vscode');
848
+ if (!existsSync(vscodeDir)) {
849
+ mkdirSync(vscodeDir, { recursive: true, mode: 0o755 });
850
+ }
851
+ writeFileSync(filePath, JSON.stringify(mergedContent, null, 2) + '\n', 'utf8');
852
+
853
+ // Create .github/copilot-instructions.md if missing
854
+ const githubDir = join(workspacePath, '.github');
855
+ if (!existsSync(githubDir)) {
856
+ mkdirSync(githubDir, { recursive: true, mode: 0o755 });
857
+ }
858
+ const copilotMdPath = join(githubDir, 'copilot-instructions.md');
859
+ if (!existsSync(copilotMdPath)) {
860
+ writeFileSync(
861
+ copilotMdPath,
862
+ `# VectorForce Context Protocol (GitHub Copilot)\n\nThis workspace uses VectorForce for architectural continuity and drift protection.\n- Architectural decisions (ADRs) and invariant constraints are tracked in VectorForce.\n- Check tasks and drift via VectorForce MCP or \`node bin/vf.js drift\`.\n- Always capture progress with \`node bin/vf.js checkpoint\`.\n`,
863
+ 'utf8'
864
+ );
865
+ }
866
+
867
+ return filePath;
868
+ }
869
+
870
+ /**
871
+ * Reversibly uninstall VectorForce from Copilot / VS Code configuration.
872
+ * @param {string} workspacePath
873
+ * @returns {boolean} whether removed
874
+ */
875
+ static uninstallCopilot(workspacePath) {
876
+ const filePath = join(workspacePath, '.vscode', 'mcp.json');
877
+ let removed = false;
878
+ if (existsSync(filePath)) {
879
+ try {
880
+ const config = JSON.parse(readFileSync(filePath, 'utf8'));
881
+ if (config?.mcpServers?.vectorforce) {
882
+ delete config.mcpServers.vectorforce;
883
+ writeFileSync(filePath, JSON.stringify(config, null, 2) + '\n', 'utf8');
884
+ removed = true;
885
+ }
886
+ } catch {}
887
+ }
888
+ return removed;
889
+ }
890
+
891
+ // ==========================================
892
+ // Kiro IDE Integration
893
+ // ==========================================
894
+
895
+ /**
896
+ * Generate configuration object for Kiro IDE (.kiro/mcp.json).
897
+ */
898
+ static getKiroServerEntry() {
899
+ return {
900
+ command: 'node',
901
+ args: [HarnessConfig.getBinPath(), 'mcp'],
902
+ env: {
903
+ VF_HARNESS: 'kiro'
904
+ }
905
+ };
906
+ }
907
+
908
+ /**
909
+ * Preview changes to Kiro IDE configuration.
910
+ * @param {string} workspacePath
911
+ */
912
+ static previewKiro(workspacePath) {
913
+ const dir = join(workspacePath, '.kiro');
914
+ const filePath = join(dir, 'mcp.json');
915
+ const kiroJsonPath = join(workspacePath, 'kiro.json');
916
+
917
+ let current = null;
918
+ if (existsSync(filePath)) {
919
+ try {
920
+ current = JSON.parse(readFileSync(filePath, 'utf8'));
921
+ } catch {
922
+ current = {};
923
+ }
924
+ }
925
+ const mergedContent = {
926
+ ...(current || {}),
927
+ mcpServers: {
928
+ ...(current?.mcpServers || {}),
929
+ vectorforce: HarnessConfig.getKiroServerEntry()
930
+ }
931
+ };
932
+
933
+ let currentKiroJson = null;
934
+ if (existsSync(kiroJsonPath)) {
935
+ try {
936
+ currentKiroJson = JSON.parse(readFileSync(kiroJsonPath, 'utf8'));
937
+ } catch {
938
+ currentKiroJson = {};
939
+ }
940
+ }
941
+ const mergedKiroJson = {
942
+ ...(currentKiroJson || {}),
943
+ mcpServers: {
944
+ ...(currentKiroJson?.mcpServers || {}),
945
+ vectorforce: HarnessConfig.getKiroServerEntry()
946
+ }
947
+ };
948
+
949
+ return {
950
+ filePath,
951
+ kiroJsonPath,
952
+ exists: existsSync(filePath) || existsSync(kiroJsonPath),
953
+ currentContent: current,
954
+ mergedContent,
955
+ mergedKiroJson
956
+ };
957
+ }
958
+
959
+ /**
960
+ * Install Kiro IDE MCP configuration and rules reversibly.
961
+ * @param {string} workspacePath
962
+ * @returns {string} filePath
963
+ */
964
+ static installKiro(workspacePath) {
965
+ const { filePath, kiroJsonPath, mergedContent, mergedKiroJson } = HarnessConfig.previewKiro(workspacePath);
966
+ const dir = join(workspacePath, '.kiro');
967
+ if (!existsSync(dir)) {
968
+ mkdirSync(dir, { recursive: true, mode: 0o755 });
969
+ }
970
+ writeFileSync(filePath, JSON.stringify(mergedContent, null, 2) + '\n', 'utf8');
971
+ writeFileSync(kiroJsonPath, JSON.stringify(mergedKiroJson, null, 2) + '\n', 'utf8');
972
+
973
+ // Create .kiro/rules.md if missing
974
+ const rulesPath = join(dir, 'rules.md');
975
+ if (!existsSync(rulesPath)) {
976
+ writeFileSync(
977
+ rulesPath,
978
+ `# VectorForce Agent Steering (Kiro IDE)\n\nThis workspace uses VectorForce for architectural continuity and drift prevention.\n- Use VectorForce MCP tools: 'list_tasks', 'check_workspace_drift', 'get_resume_briefing', 'save_checkpoint'.\n- Strictly adhere to invariant constraints and architectural decisions.\n`,
979
+ 'utf8'
980
+ );
981
+ }
982
+
983
+ return filePath;
984
+ }
985
+
986
+ /**
987
+ * Reversibly uninstall VectorForce from Kiro IDE configuration.
988
+ * @param {string} workspacePath
989
+ * @returns {boolean} whether removed
990
+ */
991
+ static uninstallKiro(workspacePath) {
992
+ const filePath = join(workspacePath, '.kiro', 'mcp.json');
993
+ const kiroJsonPath = join(workspacePath, 'kiro.json');
994
+ let removed = false;
995
+
996
+ if (existsSync(filePath)) {
997
+ try {
998
+ const config = JSON.parse(readFileSync(filePath, 'utf8'));
999
+ if (config?.mcpServers?.vectorforce) {
1000
+ delete config.mcpServers.vectorforce;
1001
+ writeFileSync(filePath, JSON.stringify(config, null, 2) + '\n', 'utf8');
1002
+ removed = true;
1003
+ }
1004
+ } catch {}
1005
+ }
1006
+
1007
+ if (existsSync(kiroJsonPath)) {
1008
+ try {
1009
+ const config = JSON.parse(readFileSync(kiroJsonPath, 'utf8'));
1010
+ if (config?.mcpServers?.vectorforce) {
1011
+ delete config.mcpServers.vectorforce;
1012
+ writeFileSync(kiroJsonPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
1013
+ removed = true;
1014
+ }
1015
+ } catch {}
1016
+ }
1017
+
1018
+ return removed;
1019
+ }
546
1020
  }
@@ -44,7 +44,7 @@ export const MCP_TOOLS = [
44
44
  task_id: { type: 'string' },
45
45
  checkpoint_id: { type: 'string', description: 'Optional specific checkpoint ID. Defaults to latest head.' },
46
46
  max_tokens: { type: 'integer', default: 4000, maximum: 8000 },
47
- destination_harness: { type: 'string', enum: ['antigravity', 'command-code', 'muse', 'muse-code', 'pi', 'codex', 'cli'] }
47
+ destination_harness: { type: 'string', enum: ['antigravity', 'command-code', 'muse', 'muse-code', 'pi', 'codex', 'cli', 'cursor', 'windsurf', 'github-copilot', 'copilot', 'kiro', 'kiro-ide'] }
48
48
  }
49
49
  }
50
50
  },
@@ -91,7 +91,7 @@ export const MCP_TOOLS = [
91
91
  task_id: { type: 'string', description: 'Kebab-case task slug' },
92
92
  recipient: { type: 'string', description: 'Target developer or audience identity' },
93
93
  checkpoint_id: { type: 'string', description: 'Optional specific checkpoint ID to export' },
94
- destination_harness: { type: 'string', enum: ['antigravity', 'command-code', 'muse', 'muse-code', 'pi', 'codex', 'cli', 'any'], default: 'any' },
94
+ destination_harness: { type: 'string', enum: ['antigravity', 'command-code', 'muse', 'muse-code', 'pi', 'codex', 'cli', 'cursor', 'windsurf', 'github-copilot', 'copilot', 'kiro', 'kiro-ide', 'any'], default: 'any' },
95
95
  preview: { type: 'boolean', default: false, description: 'Dry run preview without writing file' },
96
96
  out_path: { type: 'string', description: 'Optional custom bundle file destination' }
97
97
  }
@@ -117,7 +117,7 @@ export const MCP_TOOLS = [
117
117
  properties: {
118
118
  days: { type: 'integer', default: 7, description: 'Number of past days to include in the recap (defaults to 7)' },
119
119
  task_id: { type: 'string', description: 'Optional specific task ID to filter by' },
120
- destination_harness: { type: 'string', enum: ['antigravity', 'command-code', 'muse', 'muse-code', 'pi', 'codex', 'cli'] }
120
+ destination_harness: { type: 'string', enum: ['antigravity', 'command-code', 'muse', 'muse-code', 'pi', 'codex', 'cli', 'cursor', 'windsurf', 'github-copilot', 'copilot', 'kiro', 'kiro-ide'] }
121
121
  }
122
122
  }
123
123
  },
@@ -130,7 +130,7 @@ export const MCP_TOOLS = [
130
130
  properties: {
131
131
  task_id: { type: 'string', description: 'Kebab-case task slug' },
132
132
  checkpoint_id: { type: 'string', description: 'Optional specific checkpoint ID. Defaults to latest head.' },
133
- destination_harness: { type: 'string', enum: ['antigravity', 'command-code', 'muse', 'muse-code', 'pi', 'codex', 'cli'] },
133
+ destination_harness: { type: 'string', enum: ['antigravity', 'command-code', 'muse', 'muse-code', 'pi', 'codex', 'cli', 'cursor', 'windsurf', 'github-copilot', 'copilot', 'kiro', 'kiro-ide'] },
134
134
  model: { type: 'string', description: 'Optional model override (e.g. a Meta Llama or Muse model id)' },
135
135
  focus: { type: 'string', description: 'Optional question or focus for the reasoning pass' },
136
136
  include_code: { type: 'boolean', default: true, description: 'Ground reasoning in the live codebase index' }
@@ -5,7 +5,21 @@ import { ErrorCode, VectorForceError } from '../core/errors.js';
5
5
  export const MAX_FILE_BYTES = 8192; // 8 KiB per file
6
6
  export const MAX_TOTAL_DOCUMENT_BYTES = 65536; // 64 KiB total
7
7
  export const ALLOWED_EXTENSIONS = ['.md', '.txt'];
8
- export const APPROVED_DESTINATIONS = ['antigravity', 'command-code', 'muse', 'muse-code', 'pi', 'codex', 'cli'];
8
+ export const APPROVED_DESTINATIONS = [
9
+ 'antigravity',
10
+ 'command-code',
11
+ 'muse',
12
+ 'muse-code',
13
+ 'pi',
14
+ 'codex',
15
+ 'cli',
16
+ 'cursor',
17
+ 'windsurf',
18
+ 'github-copilot',
19
+ 'copilot',
20
+ 'kiro',
21
+ 'kiro-ide'
22
+ ];
9
23
 
10
24
  export class Authorizer {
11
25
  /**