sp-rag 0.6.11 → 0.6.13

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/README.md CHANGED
@@ -17,7 +17,7 @@ CLI để setup nhanh SP-RAG theo hướng dev-friendly:
17
17
  ## Trạng thái package
18
18
 
19
19
  - package npm public: `sp-rag`
20
- - version đang publish: `0.6.7`
20
+ - version đang publish: `0.6.13`
21
21
  - binary public: `sp-rag`
22
22
 
23
23
  ## Cài từ source trong monorepo
@@ -36,8 +36,10 @@ node dist/index.js doctor
36
36
  npx sp-rag@latest install --client codex --mcp-token <grc_pat_...> --doctor
37
37
  npx sp-rag@latest install --client cursor --scope project --cwd D:/Webs/seo-booster --mcp-token <grc_pat_...>
38
38
  npx sp-rag@latest install --client vscode --scope project --cwd D:/Webs/seo-booster --mcp-token <grc_pat_...>
39
- npx sp-rag@latest add --client claude-code --scope project --cwd D:/Webs/seo-booster
40
- npx sp-rag@latest explain --client vscode --scope project --cwd D:/Webs/seo-booster
39
+ npx sp-rag@latest add --client claude-code --scope project --cwd D:/Webs/seo-booster
40
+ npx sp-rag@latest update --client claude-code --scope project --cwd D:/Webs/seo-booster
41
+ npx sp-rag@latest uninstall --client claude-code --scope project --cwd D:/Webs/seo-booster
42
+ npx sp-rag@latest explain --client vscode --scope project --cwd D:/Webs/seo-booster
41
43
  npx sp-rag@latest token add --token <grc_pat_...>
42
44
  npx sp-rag@latest token verify --token <grc_pat_...>
43
45
  npx sp-rag@latest mcp add antigravity
@@ -50,8 +52,10 @@ Tương đương bằng `npm`:
50
52
 
51
53
  ```bash
52
54
  npm exec --yes sp-rag@latest install -- --client codex --mcp-token <grc_pat_...> --doctor
53
- npm exec --yes sp-rag@latest add -- --client claude-code --scope project --cwd D:/Webs/seo-booster
54
- npm exec --yes sp-rag@latest explain -- --client vscode --scope project --cwd D:/Webs/seo-booster
55
+ npm exec --yes sp-rag@latest add -- --client claude-code --scope project --cwd D:/Webs/seo-booster
56
+ npm exec --yes sp-rag@latest update -- --client claude-code --scope project --cwd D:/Webs/seo-booster
57
+ npm exec --yes sp-rag@latest uninstall -- --client claude-code --scope project --cwd D:/Webs/seo-booster
58
+ npm exec --yes sp-rag@latest explain -- --client vscode --scope project --cwd D:/Webs/seo-booster
55
59
  npm exec --yes sp-rag@latest token add -- --token <grc_pat_...>
56
60
  npm exec --yes sp-rag@latest token verify -- --token <grc_pat_...>
57
61
  ```
@@ -61,24 +65,29 @@ npm exec --yes sp-rag@latest token verify -- --token <grc_pat_...>
61
65
  Flow khuyên dùng sau khi đã có `grc_pat_*`:
62
66
 
63
67
  1. chạy `install` đúng một lần cho client đầu tiên, có kèm `--mcp-token`
64
- 2. từ lần sau, dùng `add --client ...` để cài thêm MCP + skill cho client khác mà không phải nhập lại token
65
- 3. khi chỉ muốn làm một nửa, dùng `mcp add` hoặc `skill install`
66
- 4. khi đổi token, chỉ cần `token add`
67
- 5. khi muốn kiểm tra máy đang được cấu hình ra sao, dùng `explain`
68
+ 2. từ lần sau, dùng `add --client ...` để cài thêm MCP + skill cho client khác mà không phải nhập lại token
69
+ 3. khi muốn cập nhật lại MCP + skill giữ token cũ, dùng `update`
70
+ 4. khi muốn gỡ sạch MCP + skill + config CLI do `sp-rag` tạo, dùng `uninstall`
71
+ 5. khi chỉ muốn làm một nửa, dùng `mcp add` hoặc `skill install`
72
+ 6. khi đổi token, chỉ cần `token add`
73
+ 7. khi muốn kiểm tra máy đang được cấu hình ra sao, dùng `explain`
68
74
 
69
75
  Ghi chú:
70
76
 
71
- - với `cursor` và `vscode` ở `scope project`, nếu Sếpp đang đứng sẵn trong repo thì có thể bỏ `--cwd`
72
- - CLI sẽ tự dùng thư mục hiện tại cho cả MCP lẫn skill
73
- - rule/agent mới đã được tăng độ ưu tiên MCP-first, giảm khả năng model nhảy thẳng sang grep/read file local
74
- - skill mới cũng dặn model tổng hợp từ `matched_passages`, `top_entities`, `top_relations`, `citations`; không nguyên `answer_brief`
77
+ - với `cursor` và `vscode` ở `scope project`, nếu Sếpp đang đứng sẵn trong repo thì có thể bỏ `--cwd`
78
+ - CLI sẽ tự dùng thư mục hiện tại cho cả MCP lẫn skill
79
+ - `update` sẽ tự tính lại target project từ `--cwd` hoặc thư mục hiện tại, không dùng target lệch project nếu user không truyền `--target-dir`
80
+ - rule/agent mới route theo intent: feature/domain/docs thì MCP trước, còn edit/debug/current-code thì kiểm tra workspace trước
81
+ - skill mới dùng hướng MCP-grounded + workspace-verified: tổng hợp từ `matched_passages`, `top_entities`, `top_relations`, `citations`, không bê nguyên `answer_brief`, và đối chiếu lại `git status --short`/file hiện tại khi cần
75
82
 
76
83
  Ví dụ:
77
84
 
78
85
  ```bash
79
- sp-rag install --client vscode --scope project --cwd D:/Webs/seo-booster --mcp-token <grc_pat_...> --doctor
80
- sp-rag add --client cursor --scope project --cwd D:/Webs/seo-booster
81
- sp-rag mcp add antigravity
86
+ sp-rag install --client vscode --scope project --cwd D:/Webs/seo-booster --mcp-token <grc_pat_...> --doctor
87
+ sp-rag add --client cursor --scope project --cwd D:/Webs/seo-booster
88
+ sp-rag update --client vscode --scope project --cwd D:/Webs/seo-booster
89
+ sp-rag uninstall --client claude-code --scope project --cwd D:/Webs/seo-booster
90
+ sp-rag mcp add antigravity
82
91
  sp-rag skill install --client vscode --scope project --cwd D:/Webs/seo-booster
83
92
  sp-rag token add --token <grc_pat_moi>
84
93
  sp-rag explain --client vscode --scope project --cwd D:/Webs/seo-booster
@@ -186,7 +195,8 @@ Ghi chú:
186
195
  ### Skill / rule / custom agent
187
196
 
188
197
  - `codex`: `~/.codex/skills/sp-rag/SKILL.md`
189
- - `claude-code`: `~/.claude/skills/sp-rag/SKILL.md`
198
+ - `claude-code` project: `.claude/skills/sp-rag/SKILL.md`
199
+ - `claude-code` global skill-only override: `~/.claude/skills/sp-rag/SKILL.md`
190
200
  - `antigravity`: `~/.gemini/antigravity/skills/sp-rag/SKILL.md`
191
201
  - `opencode`: `~/.config/opencode/skills/sp-rag/SKILL.md`
192
202
  - `cursor` project: `.cursor/rules/sp-rag.mdc`
@@ -197,8 +207,10 @@ Ghi chú:
197
207
 
198
208
  ```bash
199
209
  sp-rag install --client codex --mcp-token <grc_pat_...> --doctor
200
- sp-rag add --client cursor --scope project --cwd D:/Webs/seo-booster
201
- sp-rag explain --client codex
210
+ sp-rag add --client cursor --scope project --cwd D:/Webs/seo-booster
211
+ sp-rag update --client cursor --scope project --cwd D:/Webs/seo-booster
212
+ sp-rag uninstall --client cursor --scope project --cwd D:/Webs/seo-booster
213
+ sp-rag explain --client codex
202
214
  sp-rag token add --token <grc_pat_...>
203
215
  sp-rag token verify --token <grc_pat_...>
204
216
  sp-rag config show
@@ -212,8 +224,10 @@ sp-rag mcp add vscode --scope project --cwd D:/Webs/seo-booster
212
224
  sp-rag mcp add opencode --scope project --cwd D:/Webs/seo-booster
213
225
  sp-rag skill install --client codex
214
226
  sp-rag skill install --client cursor --scope project --cwd D:/Webs/seo-booster
215
- sp-rag skill install --client vscode --scope project --cwd D:/Webs/seo-booster
216
- sp-rag eval run --file ./examples/eval-suite.sample.json
227
+ sp-rag skill install --client vscode --scope project --cwd D:/Webs/seo-booster
228
+ sp-rag eval run --file ./examples/eval-suite.sample.json
229
+ sp-rag update --client vscode --scope project --cwd D:/Webs/seo-booster
230
+ sp-rag uninstall --client vscode --scope project --cwd D:/Webs/seo-booster
217
231
  ```
218
232
 
219
233
  ## Lệnh chính
@@ -240,8 +254,10 @@ sp-rag mcp add opencode --scope project --cwd D:/Webs/seo-booster
240
254
  sp-rag skill install --client codex
241
255
  sp-rag skill install --client cursor --scope project --cwd D:/Webs/seo-booster
242
256
  sp-rag skill install --client vscode --scope project --cwd D:/Webs/seo-booster
243
- sp-rag eval run --file ./examples/eval-suite.sample.json
244
- sp-rag update setup --client codex
257
+ sp-rag eval run --file ./examples/eval-suite.sample.json
258
+ sp-rag update --client codex
259
+ sp-rag update setup --client codex
260
+ sp-rag uninstall --client codex
245
261
  ```
246
262
 
247
263
  ## `doctor` kiểm gì
package/dist/cli.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { readFile } from 'node:fs/promises';
2
- import { loadCliConfig, saveCliConfig, } from './lib/config-store.js';
2
+ import { clearCliConfig, loadCliConfig, saveCliConfig, } from './lib/config-store.js';
3
3
  import { runEvaluationSuite } from './lib/eval.js';
4
- import { defaultBaseUrl, defaultMcpServerAlias, defaultMcpUrl, installMcpConfig, resolveMcpConfigPath, } from './lib/mcp-config.js';
4
+ import { defaultBaseUrl, defaultMcpServerAlias, defaultMcpUrl, installMcpConfig, removeMcpConfig, resolveMcpConfigPath, } from './lib/mcp-config.js';
5
5
  import { diagnoseMcpConfig, formatMcpDoctorResult } from './lib/doctor.js';
6
6
  import { fetchJson, fetchText, runDoctor } from './lib/http.js';
7
- import { installSkill, resolveSkillInstallTarget, } from './lib/skill.js';
7
+ import { installSkill, removeSkill, resolveSkillInstallTarget, } from './lib/skill.js';
8
8
  let cliVersionPromise;
9
9
  async function resolveCliVersion() {
10
10
  if (!cliVersionPromise) {
@@ -205,9 +205,11 @@ function helpText() {
205
205
  return `sp-rag - CLI cho setup, MCP, codegraph, eval và skill của SP-RAG
206
206
 
207
207
  Lệnh chính:
208
- sp-rag install --client codex|cursor|claude-code|antigravity|vscode|opencode [--base-url URL] [--mcp-url URL] [--scope global|project] [--mcp-token TOKEN] [--auth-env-var ENV_VAR] [--target-dir PATH] [--doctor]
209
- sp-rag add --client codex|cursor|claude-code|antigravity|vscode|opencode [--scope global|project] [--cwd PATH] [--target-dir PATH]
210
- sp-rag init [--base-url URL] [--mcp-url URL] [--client codex|cursor|claude-code|antigravity|vscode|opencode] [--skill-client codex|cursor|claude-code|antigravity|vscode|opencode] [--scope global|project] [--auth-env-var ENV_VAR] [--target-dir PATH]
208
+ sp-rag install --client codex|cursor|claude-code|antigravity|vscode|opencode [--base-url URL] [--mcp-url URL] [--scope global|project] [--mcp-token TOKEN] [--auth-env-var ENV_VAR] [--target-dir PATH] [--doctor]
209
+ sp-rag add --client codex|cursor|claude-code|antigravity|vscode|opencode [--scope global|project] [--cwd PATH] [--target-dir PATH]
210
+ sp-rag update [--client codex|cursor|claude-code|antigravity|vscode|opencode] [--scope global|project] [--cwd PATH] [--target-dir PATH] [--doctor]
211
+ sp-rag uninstall [--client codex|cursor|claude-code|antigravity|vscode|opencode] [--scope global|project] [--cwd PATH] [--target-dir PATH]
212
+ sp-rag init [--base-url URL] [--mcp-url URL] [--client codex|cursor|claude-code|antigravity|vscode|opencode] [--skill-client codex|cursor|claude-code|antigravity|vscode|opencode] [--scope global|project] [--auth-env-var ENV_VAR] [--target-dir PATH]
211
213
  sp-rag token add --token TOKEN
212
214
  sp-rag token verify [--token TOKEN] [--base-url URL]
213
215
  sp-rag config show
@@ -597,6 +599,50 @@ async function runUpdateSetup(parsed) {
597
599
  await runSkillInstall(parsed, defaults, client);
598
600
  }
599
601
  }
602
+ async function runUpdate(parsed) {
603
+ const defaults = await loadRuntimeDefaults(parsed);
604
+ const client = resolveSelectedClient(parsed, defaults);
605
+ if (!client) {
606
+ throw new Error('Thiếu client. Dùng sp-rag update --client <client>.');
607
+ }
608
+ await runClientSetup(parsed, defaults, client);
609
+ }
610
+ async function runUninstall(parsed) {
611
+ const defaults = await loadRuntimeDefaults(parsed);
612
+ const client = resolveSelectedClient(parsed, defaults);
613
+ if (!client) {
614
+ throw new Error('Thiếu client. Dùng sp-rag uninstall --client <client>.');
615
+ }
616
+ const scope = supportedScope(optionString(parsed, 'scope')) ?? defaults.defaultScope;
617
+ const mcpResult = await removeMcpConfig({
618
+ client,
619
+ url: optionString(parsed, 'url') ?? defaults.mcpUrl,
620
+ scope,
621
+ cwd: optionString(parsed, 'cwd'),
622
+ serverAlias: optionString(parsed, 'server-alias') ?? defaults.serverAlias,
623
+ });
624
+ process.stdout.write(`${mcpResult.removed ? 'Đã gỡ' : 'Không tìm thấy'} cấu hình MCP cho ${mcpResult.client} tại ${mcpResult.path} (${mcpResult.scope}).\n`);
625
+ const skillClient = resolveSelectedSkillClient(parsed, defaults, client);
626
+ if (skillClient) {
627
+ const skillResult = await removeSkill({
628
+ client: skillClient,
629
+ cwd: optionString(parsed, 'cwd'),
630
+ scope,
631
+ targetDir: optionString(parsed, 'target-dir'),
632
+ serverAlias: optionString(parsed, 'server-alias') ?? defaults.serverAlias,
633
+ mcpUrl: optionString(parsed, 'mcp-url') ?? defaults.mcpUrl,
634
+ docsUrl: optionString(parsed, 'docs-url') ?? defaults.docsUrl,
635
+ });
636
+ for (const removedPath of skillResult.removedPaths) {
637
+ process.stdout.write(`Đã gỡ skill cho ${skillResult.client} tại ${removedPath}\n`);
638
+ }
639
+ if (skillResult.removedPaths.length === 0) {
640
+ process.stdout.write(`Không tìm thấy skill cần gỡ cho ${skillResult.client}.\n`);
641
+ }
642
+ }
643
+ const configPath = await clearCliConfig(defaults.homeDir);
644
+ process.stdout.write(`Đã xóa config CLI tại ${configPath}\n`);
645
+ }
600
646
  export async function runCli(argv) {
601
647
  const parsed = parseArgv(argv);
602
648
  const [group, action] = parsed.positionals;
@@ -695,8 +741,17 @@ export async function runCli(argv) {
695
741
  if (group === 'eval' && action === 'run') {
696
742
  return runEval(parsed);
697
743
  }
698
- if (group === 'update' && action === 'setup') {
699
- await runUpdateSetup(parsed);
744
+ if (group === 'update' && (!action || action === 'setup')) {
745
+ if (action === 'setup') {
746
+ await runUpdateSetup(parsed);
747
+ }
748
+ else {
749
+ await runUpdate(parsed);
750
+ }
751
+ return 0;
752
+ }
753
+ if (group === 'uninstall') {
754
+ await runUninstall(parsed);
700
755
  return 0;
701
756
  }
702
757
  if (group === 'version') {
@@ -1,6 +1,6 @@
1
1
  import os from 'node:os';
2
2
  import path from 'node:path';
3
- import { mkdir, readFile, writeFile } from 'node:fs/promises';
3
+ import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
4
4
  function stripUndefined(value) {
5
5
  return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
6
6
  }
@@ -37,3 +37,8 @@ export async function saveCliConfig(config, homeDir) {
37
37
  await writeFile(filePath, `${JSON.stringify(normalized, null, 2)}\n`, 'utf8');
38
38
  return filePath;
39
39
  }
40
+ export async function clearCliConfig(homeDir) {
41
+ const filePath = resolveCliConfigPath(homeDir);
42
+ await rm(filePath, { force: true });
43
+ return filePath;
44
+ }
@@ -85,6 +85,30 @@ function upsertObjectEntryPreservingAliasByEndpoint(base, sectionKey, entryKey,
85
85
  [sectionKey]: section,
86
86
  };
87
87
  }
88
+ function removeObjectEntryByAliasOrEndpoint(base, sectionKey, entryKey, endpointKey, endpointValue) {
89
+ const section = base[sectionKey] && typeof base[sectionKey] === 'object'
90
+ ? { ...base[sectionKey] }
91
+ : {};
92
+ const targetEndpoint = normalizeEndpoint(endpointValue);
93
+ let removed = false;
94
+ for (const [alias, value] of Object.entries(section)) {
95
+ if (!value || typeof value !== 'object') {
96
+ continue;
97
+ }
98
+ const candidateEndpoint = normalizeEndpoint(value[endpointKey]);
99
+ if (alias === entryKey || (targetEndpoint && candidateEndpoint === targetEndpoint)) {
100
+ delete section[alias];
101
+ removed = true;
102
+ }
103
+ }
104
+ return {
105
+ next: {
106
+ ...base,
107
+ [sectionKey]: section,
108
+ },
109
+ removed,
110
+ };
111
+ }
88
112
  function vscodeGlobalConfigPath(home) {
89
113
  if (process.platform === 'win32') {
90
114
  const appData = process.env['APPDATA']?.trim() || path.join(home, 'AppData', 'Roaming');
@@ -122,6 +146,23 @@ export function upsertCodexConfig(existing, options) {
122
146
  }
123
147
  return `${cleaned ? `${cleaned}\n\n` : ''}${lines.join('\n')}\n`;
124
148
  }
149
+ export function removeCodexConfigContent(existing, serverAlias) {
150
+ const alias = serverAlias.trim();
151
+ const aliasPattern = escapeRegex(alias);
152
+ let removed = false;
153
+ const withoutHeaders = existing.replace(new RegExp(`(?:^|\\n)\\[mcp_servers\\.(?:"${aliasPattern}"|${aliasPattern})\\.headers\\][\\s\\S]*?(?=(?:\\n\\[[^\\n]+\\])|$)`, 'g'), () => {
154
+ removed = true;
155
+ return '';
156
+ });
157
+ const cleaned = withoutHeaders.replace(new RegExp(`(?:^|\\n)\\[mcp_servers\\.(?:"${aliasPattern}"|${aliasPattern})\\][\\s\\S]*?(?=(?:\\n\\[[^\\n]+\\])|$)`, 'g'), () => {
158
+ removed = true;
159
+ return '';
160
+ });
161
+ return {
162
+ content: `${cleaned.trimEnd()}${cleaned.trimEnd() ? '\n' : ''}`,
163
+ removed,
164
+ };
165
+ }
125
166
  export function upsertJsonMcpConfig(existing, options) {
126
167
  const base = parseJsonObject(existing);
127
168
  const serverConfig = withHeaders({
@@ -279,3 +320,58 @@ export async function installMcpConfig(options) {
279
320
  await writeFile(resolved.path, content, 'utf8');
280
321
  return resolved;
281
322
  }
323
+ export async function removeMcpConfig(options) {
324
+ const resolved = resolveMcpConfigPath(options);
325
+ const existing = await readFile(resolved.path, 'utf8').catch((error) => {
326
+ if (error.code === 'ENOENT') {
327
+ return '';
328
+ }
329
+ throw error;
330
+ });
331
+ const alias = options.serverAlias?.trim() || defaultMcpServerAlias();
332
+ const url = options.url.trim();
333
+ let content = existing;
334
+ let removed = false;
335
+ if (existing.trim()) {
336
+ switch (resolved.client) {
337
+ case 'codex': {
338
+ const result = removeCodexConfigContent(existing, alias);
339
+ content = result.content;
340
+ removed = result.removed;
341
+ break;
342
+ }
343
+ case 'cursor':
344
+ case 'claude-code': {
345
+ const result = removeObjectEntryByAliasOrEndpoint(parseJsonObject(existing), 'mcpServers', alias, 'url', url);
346
+ content = `${JSON.stringify(result.next, null, 2)}\n`;
347
+ removed = result.removed;
348
+ break;
349
+ }
350
+ case 'antigravity': {
351
+ const result = removeObjectEntryByAliasOrEndpoint(parseJsonObject(existing), 'mcpServers', alias, 'serverUrl', url);
352
+ content = `${JSON.stringify(result.next, null, 2)}\n`;
353
+ removed = result.removed;
354
+ break;
355
+ }
356
+ case 'vscode': {
357
+ const result = removeObjectEntryByAliasOrEndpoint(parseJsonObject(existing), 'servers', alias, 'url', url);
358
+ content = `${JSON.stringify(result.next, null, 2)}\n`;
359
+ removed = result.removed;
360
+ break;
361
+ }
362
+ case 'opencode': {
363
+ const result = removeObjectEntryByAliasOrEndpoint(parseJsonObject(existing), 'mcp', alias, 'url', url);
364
+ content = `${JSON.stringify(result.next, null, 2)}\n`;
365
+ removed = result.removed;
366
+ break;
367
+ }
368
+ }
369
+ }
370
+ if (removed) {
371
+ await writeFile(resolved.path, content, 'utf8');
372
+ }
373
+ return {
374
+ ...resolved,
375
+ removed,
376
+ };
377
+ }
package/dist/lib/skill.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import os from 'node:os';
2
2
  import path from 'node:path';
3
- import { mkdir, writeFile } from 'node:fs/promises';
3
+ import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
4
4
  const seoBoosterRemoteUrl = 'https://gitlab.com/secomapp/development/seo-booster.git';
5
5
  const seoBoosterProjectGuard = [
6
6
  '- SP-RAG chỉ dành cho repo seo-booster.',
@@ -72,7 +72,7 @@ export function defaultSkillDir(client = 'codex', cwd, scope) {
72
72
  function renderSkillMarkdown(context) {
73
73
  return `---
74
74
  name: sp-rag
75
- description: Use SP-RAG whenever the user asks about this codebase, internal business domain, rendered docs, import inventory, or codegraph sync status. You must call SP-RAG MCP tools first before answering from memory or reading local files.
75
+ description: Use SP-RAG for seo-booster codebase, feature, domain, rendered-docs, import-inventory, or codegraph freshness work that needs grounded evidence.
76
76
  ---
77
77
 
78
78
  # SP-RAG
@@ -84,29 +84,43 @@ Docs URL: \`${context.docsUrl}\`
84
84
 
85
85
  ## When To Use This Skill
86
86
 
87
- - Use this skill whenever the request is about the internal codebase, business workflows, rendered docs, import inventory, or sync state.
88
- - Use this skill when grounded evidence matters more than memory or intuition.
89
- - Use this skill when the answer should come from MCP tools or rendered docs before freeform reasoning.
87
+ - Use SP-RAG whenever the request is about seo-booster codebase, features, business workflows, rendered docs, import inventory, or sync state.
88
+ - Use this skill for seo-booster codebase, feature, business workflow, rendered docs, import inventory, and sync-state questions.
89
+ - The operating model is MCP-grounded, workspace-verified.
90
+ - Do not treat MCP as the only source. MCP gives context; current workspace files and git state verify the final answer.
90
91
 
91
- ## Recommended Workflow
92
+ ## Intent Routing
93
+
94
+ - For feature, domain, architecture, workflow, docs, or "what does this do" questions: call \`${context.serverAlias}\` MCP first, usually \`query_context\`, then verify with workspace files when implementation details matter.
95
+ - For current-code, edit, bug, failing-test, local-error, or "why is this broken right now" work: inspect the workspace first with \`git status --short\`, \`rg\`, and direct file reads, then use MCP to widen context if needed.
96
+ - For mixed questions: get MCP context, inspect current files, compare both, then answer.
97
+ - For docs questions, use \`get_rendered_docs\` when public, function, or dev docs may already answer the question.
98
+ - For sync freshness and operations, use \`get_sync_status\`, \`get_sync_runs\`, and \`get_sync_metrics\`. Only use \`trigger_code_graph_sync\` when the user explicitly asks or stale evidence is the confirmed blocker.
99
+
100
+ ## Workspace Verification
101
+
102
+ 1. Run or mentally account for \`git status --short\` before relying on MCP for current behavior.
103
+ 2. If MCP cites files, inspect the current workspace version of those files when the answer depends on exact code.
104
+ 3. If changed files are related to the question, current workspace files override MCP evidence.
105
+ 4. If MCP and workspace disagree, say the graph may be stale and explain which source you are trusting.
106
+
107
+ ## Expand Evidence
92
108
 
93
- 1. Call \`healthz\` if the MCP server might be unavailable or the connection is brand new.
94
- 2. Use \`query_context\` for architecture, domain, entities, relations, and business flow questions.
95
- 3. Use \`get_rendered_docs\` for public, function, or dev docs that were already rendered from the latest graph.
96
- 4. Use \`get_sync_status\`, \`get_sync_runs\`, or \`get_sync_metrics\` when you need to verify commit freshness, investigate failures, or inspect operational history.
97
- 5. Only call \`trigger_code_graph_sync\` when the user explicitly asks to refresh the graph or when a stale graph is the confirmed blocker.
98
- 6. After \`query_context\` returns, synthesize the final answer from \`matched_passages\`, \`top_entities\`, \`top_relations\`, and \`citations\`. Treat \`answer_brief\` as a hint only.
109
+ - After \`query_context\`, synthesize from \`matched_passages\`, \`top_entities\`, \`top_relations\`, \`citations\`, and \`feature_memory\` diagnostics when present.
110
+ - Treat \`answer_brief\` as a hint only.
111
+ - Do not stop at the first one or two MCP citations for broad feature questions.
112
+ - Expand through related symbols, callers, services, controllers, jobs, routes, models, components, and tests using workspace search when needed.
113
+ - Prefer rendered docs when they answer business behavior, but verify current code before making implementation claims.
99
114
 
100
115
  ## Guardrails
101
116
 
102
117
  ${seoBoosterProjectGuard}
103
- - You must call SP-RAG MCP tools first for codebase or domain questions before using local workspace search, grep, or file reads.
104
- - Prefer MCP-grounded answers before relying on memory.
105
- - Treat \`answer_brief\` as a hint only. Prefer the richer evidence in \`matched_passages\`, \`top_entities\`, \`top_relations\`, and \`citations\` when writing the final answer.
106
- - If the evidence may be stale, say so clearly and mention that the graph or docs may need a refresh.
118
+ - Find root cause before fixing bugs.
119
+ - Use evidence before conclusions; do not claim completion without verification.
120
+ - For behavior changes, write or update tests before implementation when feasible.
121
+ - If evidence may be stale, say so clearly and mention that the graph or docs may need a refresh.
107
122
  - Do not trigger sync or import actions unless the user asked for it or the workflow truly requires it.
108
- - When rendered docs already answer the question, cite or summarize those docs instead of rewriting everything from scratch.
109
- - Only fall back to local workspace search or file reads after MCP is unavailable or clearly lacks the needed evidence, and say that you are falling back.
123
+ - When rendered docs already answer the question, cite or summarize those docs, then check current code if the answer depends on implementation details.
110
124
  `;
111
125
  }
112
126
  function renderCursorRule(context) {
@@ -119,14 +133,16 @@ alwaysApply: true
119
133
  # SP-RAG
120
134
 
121
135
  ${seoBoosterProjectGuard}
122
- - You must call the \`${context.serverAlias}\` MCP server first before using local workspace search, grep, or file reads for codebase and domain questions.
136
+ - Route by intent before choosing tools.
137
+ - Use the \`${context.serverAlias}\` MCP server first for feature, domain, architecture, workflow, docs, and "what does this do" questions.
138
+ - Use workspace search first for current-code, edit, bug, and test-failure work.
139
+ - Verify MCP evidence against \`git status --short\` and current workspace files before making implementation claims.
123
140
  - Use rendered docs from \`${context.docsUrl}\` when documentation already answers the question.
124
- - For architecture, domain, entities, relations, and business workflow questions, query MCP first and only then synthesize the answer.
125
141
  - Treat \`answer_brief\` only as a hint. Build the final answer from \`matched_passages\`, \`top_entities\`, \`top_relations\`, and \`citations\`.
142
+ - Do not stop at the first one or two MCP citations for broad feature questions. Expand through related files, symbols, services, controllers, jobs, components, and tests.
126
143
  - For freshness or operational questions, check sync status, recent runs, and metrics before assuming the graph is current.
127
144
  - Only trigger codegraph sync when the user explicitly asks for it or stale evidence is the confirmed blocker.
128
145
  - If the evidence may be stale, say so clearly.
129
- - Only fall back to local workspace search after MCP is unavailable or clearly lacks the needed evidence, and say that you are falling back.
130
146
  `;
131
147
  }
132
148
  function renderVsCodeAgent(context) {
@@ -140,41 +156,44 @@ You are the SP-RAG custom agent for this workspace.
140
156
 
141
157
  Use the \`${context.serverAlias}\` MCP server at \`${context.mcpUrl}\` and the rendered docs URL \`${context.docsUrl}\` as your grounded source of truth.
142
158
 
143
- You must call an SP-RAG MCP tool before using local workspace search, grep, or file reads for codebase and domain questions.
159
+ Route by intent before choosing tools. MCP gives the semantic map; the current workspace verifies exact code.
144
160
 
145
161
  ## Recommended Workflow
146
162
 
147
- 1. Start with \`healthz\` if connectivity or freshness is uncertain.
148
- 2. Use \`query_context\` for architecture, domain, entities, relations, and workflow questions.
163
+ 1. For feature, domain, architecture, workflow, docs, and "what does this do" questions, use \`query_context\` first.
164
+ 2. For current-code, edit, debug, failing-test, and local-error work, inspect the workspace first with \`git status --short\`, \`rg\`, and direct file reads.
149
165
  3. Use \`get_rendered_docs\` when public, function, or dev docs may already answer the question.
150
166
  4. Use \`get_sync_status\`, \`get_sync_runs\`, or \`get_sync_metrics\` for freshness, incident review, or operational debugging.
151
- 5. Trigger codegraph sync only when the user explicitly requests a refresh or stale evidence is the confirmed blocker.
152
- 6. After \`query_context\` returns, synthesize the final answer from \`matched_passages\`, \`top_entities\`, \`top_relations\`, and \`citations\`. Treat \`answer_brief\` as a hint.
167
+ 5. After MCP returns, verify important citations against current workspace files if the answer depends on exact implementation.
168
+ 6. Expand beyond the first one or two MCP citations for broad feature questions. Search related symbols, callers, services, controllers, jobs, routes, models, components, and tests.
169
+ 7. Trigger codegraph sync only when the user explicitly requests a refresh or stale evidence is the confirmed blocker.
153
170
 
154
171
  ## Guardrails
155
172
 
156
173
  ${seoBoosterProjectGuard}
157
- - Prefer MCP-grounded evidence before answering from memory.
174
+ - Prefer MCP-grounded evidence before answering from memory, but current workspace files override MCP evidence when they differ.
158
175
  - Treat \`answer_brief\` as a hint. Prefer the richer evidence in \`matched_passages\`, \`top_entities\`, \`top_relations\`, and \`citations\` when writing the final answer.
159
- - Do not use local workspace search, grep, or file reads until SP-RAG MCP has been tried first for the current question.
160
176
  - When evidence may be stale, say so clearly and mention that a refresh might be needed.
161
177
  - Do not trigger sync or import actions unless the workflow truly requires it.
162
178
  - When rendered docs already answer the question, summarize those docs instead of rewriting everything from scratch.
163
- - Only fall back to local workspace search or file reads after MCP is unavailable or clearly lacks the needed evidence, and say that you are falling back.
179
+ - Find root cause before fixes, write or update tests for behavior changes when feasible, and verify before claiming completion.
164
180
  `;
165
181
  }
166
182
  function renderVsCodeAlwaysOnInstructions(context) {
167
183
  return `# SP-RAG workspace instructions
168
184
 
169
185
  ${seoBoosterProjectGuard}
170
- - Always use the \`${context.serverAlias}\` MCP server first for codebase, domain, architecture, workflow, and operational questions before local workspace search, grep, or file reads.
186
+ - Route by intent before choosing tools.
187
+ - Use the \`${context.serverAlias}\` MCP server first for feature, domain, architecture, workflow, docs, and "what does this do" questions.
188
+ - Use workspace inspection first for current-code, edit, debug, failing-test, and local-error work.
189
+ - Verify MCP evidence against current workspace state, including \`git status --short\` and current file contents when implementation details matter.
171
190
  - Start with \`healthz\` only when connectivity is uncertain or the session is new.
172
- - Use \`query_context\` first for feature, entity, relation, and business-flow questions.
173
191
  - When \`query_context\` returns, synthesize the final answer from \`matched_passages\`, \`top_entities\`, \`top_relations\`, and \`citations\`.
174
192
  - Treat \`answer_brief\` as a hint only, not the final answer.
193
+ - Expand beyond the first one or two MCP citations for broad feature questions.
175
194
  - Use \`get_rendered_docs\` when rendered docs can answer the question faster than raw code inspection.
176
195
  - Only trigger codegraph sync when the user explicitly asks for it or stale graph evidence is the confirmed blocker.
177
- - If MCP is unavailable or clearly lacks evidence, say so explicitly before falling back to local workspace search or file reads.
196
+ - If MCP and current workspace files disagree, say MCP may be stale and trust the current workspace for implementation details.
178
197
  `;
179
198
  }
180
199
  function renderSkillArtifact(context) {
@@ -260,6 +279,41 @@ export async function installSkill(options = {}) {
260
279
  paths,
261
280
  };
262
281
  }
282
+ async function removeIfSpRagArtifact(filePath) {
283
+ const content = await readFile(filePath, 'utf8').catch((error) => {
284
+ if (error.code === 'ENOENT') {
285
+ return null;
286
+ }
287
+ throw error;
288
+ });
289
+ if (content === null) {
290
+ return false;
291
+ }
292
+ if (!content.includes('SP-RAG') && !content.includes('sp-rag')) {
293
+ return false;
294
+ }
295
+ await rm(filePath, { force: true });
296
+ return true;
297
+ }
298
+ export async function removeSkill(options = {}) {
299
+ const resolved = resolveSkillInstallTarget(options);
300
+ const context = createSkillContext(options, resolved.client);
301
+ const paths = [
302
+ resolved.path,
303
+ ...resolveAdditionalSkillArtifacts(options, resolved, context).map((entry) => entry.path),
304
+ ];
305
+ const removedPaths = [];
306
+ for (const filePath of paths) {
307
+ if (await removeIfSpRagArtifact(filePath)) {
308
+ removedPaths.push(filePath);
309
+ }
310
+ }
311
+ return {
312
+ client: resolved.client,
313
+ paths,
314
+ removedPaths,
315
+ };
316
+ }
263
317
  export async function installCodexSkill(options = {}) {
264
318
  return installSkill({
265
319
  ...options,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sp-rag",
3
- "version": "0.6.11",
3
+ "version": "0.6.13",
4
4
  "description": "CLI cho setup MCP, codegraph GitNexus và skill của SP-RAG",
5
5
  "type": "module",
6
6
  "files": [