sp-rag 0.6.14 → 0.6.16

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
@@ -1,4 +1,20 @@
1
- # `sp-rag`
1
+ # `sp-rag`
2
+
3
+ ## Context boundary
4
+
5
+ `sp-rag` exists to connect IDEs/agents to SP-RAG evidence for the `seo-booster`
6
+ application.
7
+
8
+ - `graphrag-core` is the SP-RAG platform and knowledge runtime.
9
+ - `seo-booster` is the target application and source workspace for app/business review.
10
+ - `GitNexus`/codegraph references are platform internals or artifact sources, not
11
+ the project to review unless the task explicitly asks for codegraph debugging.
12
+ - For project-scoped installs, use `--cwd <seo-booster-workspace>`.
13
+ - Do not install project-scoped VS Code/Cursor/Claude config into `<graphrag-core-workspace>` when the goal is to review `seo-booster`.
14
+ - Use `<graphrag-core-workspace>` as `--cwd` only when developing or debugging this SP-RAG platform itself.
15
+ - `<seo-booster-workspace>` and `<graphrag-core-workspace>` are placeholders, not literal paths. Replace them with the local checkout path on each machine, or omit `--cwd` when already inside the target repo.
16
+
17
+ Canonical boundary doc: [../../docs/runbooks/sp-rag-seo-booster-boundary.md](../../docs/runbooks/sp-rag-seo-booster-boundary.md)
2
18
 
3
19
  CLI để setup nhanh SP-RAG theo hướng dev-friendly:
4
20
 
@@ -16,9 +32,10 @@ CLI để setup nhanh SP-RAG theo hướng dev-friendly:
16
32
 
17
33
  ## Trạng thái package
18
34
 
19
- - package npm public: `sp-rag`
20
- - version đang publish: `0.6.14`
21
- - binary public: `sp-rag`
35
+ - package npm public: `sp-rag`
36
+ - version trong repo: `0.6.16`
37
+ - npm latest hiện tại: `0.6.15`
38
+ - binary public: `sp-rag`
22
39
 
23
40
  ## Cài từ source trong monorepo
24
41
 
@@ -32,30 +49,32 @@ node dist/index.js doctor
32
49
 
33
50
  ## Cài nhanh qua `npx`
34
51
 
35
- ```bash
36
- npx sp-rag@latest install --client codex --mcp-token <grc_pat_...> --doctor
37
- npx sp-rag@latest install --client cursor --scope project --cwd D:/Webs/seo-booster --mcp-token <grc_pat_...>
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 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
52
+ ```bash
53
+ npx sp-rag@latest token add --token <grc_pat_...>
54
+ npx sp-rag@latest install --client codex --doctor
55
+ npx sp-rag@latest install --client cursor --cwd <seo-booster-workspace>
56
+ npx sp-rag@latest install --client vscode --cwd <seo-booster-workspace>
57
+ npx sp-rag@latest add --client claude-code --scope project --cwd <seo-booster-workspace>
58
+ npx sp-rag@latest update --client claude-code --scope project --cwd <seo-booster-workspace>
59
+ npx sp-rag@latest uninstall --client claude-code --scope project --cwd <seo-booster-workspace>
60
+ npx sp-rag@latest explain --client vscode --scope project --cwd <seo-booster-workspace>
43
61
  npx sp-rag@latest token add --token <grc_pat_...>
44
62
  npx sp-rag@latest token verify --token <grc_pat_...>
45
63
  npx sp-rag@latest mcp add antigravity
46
- npx sp-rag@latest mcp add opencode --scope project --cwd D:/Webs/seo-booster
47
- npx sp-rag@latest skill install --client cursor --scope project --cwd D:/Webs/seo-booster
48
- npx sp-rag@latest skill install --client vscode --scope project --cwd D:/Webs/seo-booster
64
+ npx sp-rag@latest mcp add opencode --scope project --cwd <seo-booster-workspace>
65
+ npx sp-rag@latest skill install --client cursor --scope project --cwd <seo-booster-workspace>
66
+ npx sp-rag@latest skill install --client vscode --scope project --cwd <seo-booster-workspace>
49
67
  ```
50
68
 
51
69
  Tương đương bằng `npm`:
52
70
 
53
- ```bash
54
- npm exec --yes sp-rag@latest install -- --client codex --mcp-token <grc_pat_...> --doctor
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
71
+ ```bash
72
+ npm exec --yes sp-rag@latest token add -- --token <grc_pat_...>
73
+ npm exec --yes sp-rag@latest install -- --client codex --doctor
74
+ npm exec --yes sp-rag@latest add -- --client claude-code --scope project --cwd <seo-booster-workspace>
75
+ npm exec --yes sp-rag@latest update -- --client claude-code --scope project --cwd <seo-booster-workspace>
76
+ npm exec --yes sp-rag@latest uninstall -- --client claude-code --scope project --cwd <seo-booster-workspace>
77
+ npm exec --yes sp-rag@latest explain -- --client vscode --scope project --cwd <seo-booster-workspace>
59
78
  npm exec --yes sp-rag@latest token add -- --token <grc_pat_...>
60
79
  npm exec --yes sp-rag@latest token verify -- --token <grc_pat_...>
61
80
  ```
@@ -64,13 +83,14 @@ npm exec --yes sp-rag@latest token verify -- --token <grc_pat_...>
64
83
 
65
84
  Flow khuyên dùng sau khi đã có `grc_pat_*`:
66
85
 
67
- 1. chạy `install` đúng một lần cho client đầu tiên, kèm `--mcp-token`
68
- 2. từ lần sau, dùng `add --client ...` để cài thêm MCP + skill cho client khác không phải nhập lại token
69
- 3. khi muốn cập nhật lại MCP + skill mà 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`
86
+ 1. chạy `sp-rag token add --token <grc_pat_...>` đúng một lần để lưu token
87
+ 2. chạy `install` cho client đầu tiên, không cần kèm `--mcp-token`
88
+ 3. từ lần sau, dùng `add --client ...` để cài thêm MCP + skill cho client khác không phải nhập lại token
89
+ 4. khi muốn cập nhật lại MCP + skill giữ token cũ, dùng `update`
90
+ 5. khi muốn gỡ sạch MCP + skill + config CLI do `sp-rag` tạo, dùng `uninstall`
91
+ 6. khi chỉ muốn làm một nửa, dùng `mcp add` hoặc `skill install`
92
+ 7. khi đổi token, chỉ cần `token add`
93
+ 8. khi muốn kiểm tra máy đang được cấu hình ra sao, dùng `explain`
74
94
 
75
95
  Ghi chú:
76
96
 
@@ -82,15 +102,16 @@ Ghi chú:
82
102
 
83
103
  Ví dụ:
84
104
 
85
- ```bash
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
105
+ ```bash
106
+ sp-rag token add --token <grc_pat_...>
107
+ sp-rag install --client vscode --cwd <seo-booster-workspace> --doctor
108
+ sp-rag add --client cursor --cwd <seo-booster-workspace>
109
+ sp-rag update --client vscode --cwd <seo-booster-workspace>
110
+ sp-rag uninstall --client claude-code --scope project --cwd <seo-booster-workspace>
90
111
  sp-rag mcp add antigravity
91
- sp-rag skill install --client vscode --scope project --cwd D:/Webs/seo-booster
112
+ sp-rag skill install --client vscode --scope project --cwd <seo-booster-workspace>
92
113
  sp-rag token add --token <grc_pat_moi>
93
- sp-rag explain --client vscode --scope project --cwd D:/Webs/seo-booster
114
+ sp-rag explain --client vscode --scope project --cwd <seo-booster-workspace>
94
115
  ```
95
116
 
96
117
  ## Lấy token ở đâu
@@ -137,19 +158,20 @@ curl -X POST https://sp-rag.secomapp.com/api/v1/account/personal-access-tokens \
137
158
 
138
159
  Response sẽ trả `generated_token`, chính là token `grc_pat_*` để đưa vào `sp-rag`.
139
160
 
140
- Ví dụ dev dùng token trực tiếp:
141
-
142
- ```bash
143
- npx sp-rag@latest install --client cursor --scope project --cwd D:/Webs/seo-booster --mcp-token <grc_pat_...>
144
- npx sp-rag@latest token verify --token <grc_pat_...>
145
- npx sp-rag@latest explain --client cursor --scope project --cwd D:/Webs/seo-booster
146
- ```
161
+ Ví dụ dev lưu token một lần rồi cài client:
162
+
163
+ ```bash
164
+ npx sp-rag@latest token add --token <grc_pat_...>
165
+ npx sp-rag@latest install --client cursor --cwd <seo-booster-workspace>
166
+ npx sp-rag@latest token verify --token <grc_pat_...>
167
+ npx sp-rag@latest explain --client cursor --scope project --cwd <seo-booster-workspace>
168
+ ```
147
169
 
148
170
  Hoặc dùng biến môi trường:
149
171
 
150
172
  ```bash
151
173
  $env:GRAPHRAG_MCP_TOKEN="<grc_pat_...>"
152
- npx sp-rag@latest mcp add vscode --scope project --cwd D:/Webs/seo-booster --auth-env-var GRAPHRAG_MCP_TOKEN
174
+ npx sp-rag@latest mcp add vscode --scope project --cwd <seo-booster-workspace> --auth-env-var GRAPHRAG_MCP_TOKEN
153
175
  npx sp-rag@latest token verify --token $env:GRAPHRAG_MCP_TOKEN
154
176
  ```
155
177
 
@@ -205,14 +227,14 @@ Ghi chú:
205
227
 
206
228
  ## Luồng khuyên dùng cho dev mới
207
229
 
208
- ```bash
209
- sp-rag install --client codex --mcp-token <grc_pat_...> --doctor
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
230
+ ```bash
231
+ sp-rag token add --token <grc_pat_...>
232
+ sp-rag install --client codex --doctor
233
+ sp-rag add --client cursor --cwd <seo-booster-workspace>
234
+ sp-rag update --client cursor --cwd <seo-booster-workspace>
235
+ sp-rag uninstall --client cursor --scope project --cwd <seo-booster-workspace>
213
236
  sp-rag explain --client codex
214
- sp-rag token add --token <grc_pat_...>
215
- sp-rag token verify --token <grc_pat_...>
237
+ sp-rag token verify --token <grc_pat_...>
216
238
  sp-rag config show
217
239
  sp-rag codegraph status
218
240
  sp-rag codegraph watch --interval-ms 2000
@@ -220,27 +242,29 @@ sp-rag codegraph runs --limit 5
220
242
  sp-rag codegraph metrics
221
243
  sp-rag codegraph recover --reason "Ops dọn stale run sau crash"
222
244
  sp-rag mcp add antigravity
223
- sp-rag mcp add vscode --scope project --cwd D:/Webs/seo-booster
224
- sp-rag mcp add opencode --scope project --cwd D:/Webs/seo-booster
245
+ sp-rag mcp add vscode --scope project --cwd <seo-booster-workspace>
246
+ sp-rag mcp add opencode --scope project --cwd <seo-booster-workspace>
225
247
  sp-rag skill install --client codex
226
- sp-rag skill install --client cursor --scope project --cwd D:/Webs/seo-booster
227
- sp-rag skill install --client vscode --scope project --cwd D:/Webs/seo-booster
248
+ sp-rag skill install --client cursor --scope project --cwd <seo-booster-workspace>
249
+ sp-rag skill install --client vscode --scope project --cwd <seo-booster-workspace>
228
250
  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
251
+ sp-rag update --client vscode --scope project --cwd <seo-booster-workspace>
252
+ sp-rag uninstall --client vscode --scope project --cwd <seo-booster-workspace>
231
253
  ```
232
254
 
233
255
  ## Lệnh chính
234
256
 
235
- ```bash
236
- sp-rag install --client codex --mcp-token <grc_pat_...> --doctor
237
- sp-rag add --client cursor --scope project --cwd D:/Webs/seo-booster
238
- sp-rag explain --client codex
239
- sp-rag token add --token <grc_pat_...>
240
- sp-rag token verify --token <grc_pat_...>
241
- sp-rag config show
242
- sp-rag doctor
243
- sp-rag codegraph status
257
+ ```bash
258
+ sp-rag token add --token <grc_pat_...>
259
+ sp-rag install --client codex --doctor
260
+ sp-rag add --client cursor --cwd <seo-booster-workspace>
261
+ sp-rag explain --client codex
262
+ sp-rag token verify --token <grc_pat_...>
263
+ sp-rag config show
264
+ sp-rag doctor
265
+ sp-rag audit install --client codex
266
+ sp-rag audit signal --file ./sp-audit-signal.json
267
+ sp-rag codegraph status
244
268
  sp-rag codegraph watch --interval-ms 2000
245
269
  sp-rag codegraph runs --limit 10
246
270
  sp-rag codegraph metrics
@@ -249,11 +273,11 @@ sp-rag codegraph sync --branch master --commit-sha <sha> --webhook-token <token
249
273
  sp-rag docs get public --format md
250
274
  sp-rag mcp add codex
251
275
  sp-rag mcp add antigravity
252
- sp-rag mcp add vscode --scope project --cwd D:/Webs/seo-booster
253
- sp-rag mcp add opencode --scope project --cwd D:/Webs/seo-booster
276
+ sp-rag mcp add vscode --scope project --cwd <seo-booster-workspace>
277
+ sp-rag mcp add opencode --scope project --cwd <seo-booster-workspace>
254
278
  sp-rag skill install --client codex
255
- sp-rag skill install --client cursor --scope project --cwd D:/Webs/seo-booster
256
- sp-rag skill install --client vscode --scope project --cwd D:/Webs/seo-booster
279
+ sp-rag skill install --client cursor --scope project --cwd <seo-booster-workspace>
280
+ sp-rag skill install --client vscode --scope project --cwd <seo-booster-workspace>
257
281
  sp-rag eval run --file ./examples/eval-suite.sample.json
258
282
  sp-rag update --client codex
259
283
  sp-rag update setup --client codex
@@ -266,15 +290,16 @@ sp-rag uninstall --client codex
266
290
 
267
291
  - ping các endpoint `api`, `mcp`, `codegraph`
268
292
  - đọc đúng file MCP của client để kiểm:
269
- - IDE đang nhìn vào file nào
270
- - server entry nào được match theo alias hoặc theo endpoint
271
- - `Authorization` đang là token literal, env var hợp lệ, hay đang thiếu
272
- - khả năng IDE sẽ bật link đăng nhập OAuth
293
+ - IDE đang nhìn vào file nào
294
+ - server entry nào được match theo alias hoặc theo endpoint
295
+ - `Authorization` đang là token literal, env var hợp lệ, hay đang thiếu
296
+ - riêng Codex, xác nhận `bearer_token_env_var`/`http_headers` thay legacy `[mcp_servers.<alias>.headers]`
297
+ - khả năng IDE sẽ bật link đăng nhập OAuth
273
298
 
274
299
  Ví dụ:
275
300
 
276
301
  ```bash
277
- sp-rag doctor --client vscode --scope project --cwd D:/Webs/seo-booster
302
+ sp-rag doctor --client vscode --scope project --cwd <seo-booster-workspace>
278
303
  ```
279
304
 
280
305
  Nếu output có dòng:
@@ -303,7 +328,55 @@ Giá trị mặc định:
303
328
 
304
329
  - base URL: `https://sp-rag.secomapp.com`
305
330
  - MCP URL: `https://sp-rag.secomapp.com/mcp`
306
- - alias MCP: `sp-rag`
331
+ - alias MCP: `sp-rag`
332
+
333
+ ## Audit workflow `sp-rag audit`
334
+
335
+ `sp-audit` khong phai la CLI moi. No la skill/agent workflow duoc cai bang
336
+ CLI hien tai `sp-rag`.
337
+
338
+ Lenh chuan de cai audit workflow:
339
+
340
+ ```bash
341
+ sp-rag audit install --client codex
342
+ ```
343
+
344
+ Lenh nay:
345
+
346
+ - cai MCP config cho client da chon
347
+ - cai native skill/rule/custom agent `sp-audit`
348
+ - tai su dung config/token cua `sp-rag`
349
+ - van la cung binary `sp-rag`, tuong tu `sp-rag add` hay `sp-rag doctor`
350
+ - neu token chua duoc luu, chay `sp-rag token add --token <grc_pat_...>` mot lan truoc do
351
+ - scope mac dinh suy theo client: `codex` la global, `cursor`/`vscode` la project
352
+
353
+ Neu chi muon cai lai skill audit ma khong cham vao MCP config, co the dung
354
+ low-level command:
355
+
356
+ ```bash
357
+ sp-rag skill install --client codex --name sp-audit
358
+ ```
359
+
360
+ Day JSON signal do `sp-audit` tao ra vao server memory import path:
361
+
362
+ ```bash
363
+ sp-rag audit signal --file ./sp-audit-signal.json
364
+ ```
365
+
366
+ `audit signal` posts through the existing knowledge-source import API with
367
+ `normalizer_provider=heuristic` and `warm_cache=false`, so small audit feedback
368
+ records do not block on AI normalization or semantic-cache materialization.
369
+
370
+ Native paths cua audit workflow:
371
+
372
+ - Codex: `~/.codex/skills/sp-audit/SKILL.md`
373
+ - Claude Code: `.claude/skills/sp-audit/SKILL.md` hoac `~/.claude/skills/sp-audit/SKILL.md`
374
+ - Antigravity: `~/.gemini/antigravity/skills/sp-audit/SKILL.md`
375
+ - OpenCode: `~/.config/opencode/skills/sp-audit/SKILL.md`
376
+ - Cursor: `.cursor/rules/sp-audit.mdc`
377
+ - VS Code: `.github/agents/sp-audit.agent.md` hoac `~/.copilot/agents/sp-audit.agent.md`
378
+
379
+ Chi tiet: [Runbook `sp-rag audit`](../../docs/runbooks/sp-audit.md).
307
380
 
308
381
  ## Evaluation mẫu
309
382
 
@@ -312,6 +385,7 @@ Giá trị mặc định:
312
385
  ## Tài liệu thêm
313
386
 
314
387
  - [Hướng dẫn dev sử dụng SP-RAG](../../docs/runbooks/dev-usage-guide.md)
315
- - [Runbook CLI `sp-rag`](../../docs/runbooks/sp-rag-cli.md)
388
+ - [Runbook CLI `sp-rag`](../../docs/runbooks/sp-rag-cli.md)
389
+ - [Runbook `sp-rag audit`](../../docs/runbooks/sp-audit.md)
316
390
  - [Runbook phát hành CLI `sp-rag`](../../docs/runbooks/sp-rag-cli-release.md)
317
391
  - [Runbook MCP Public](../../docs/runbooks/mcp-public-clients.md)
package/dist/cli.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import { readFile } from 'node:fs/promises';
2
+ import path from 'node:path';
2
3
  import { clearCliConfig, loadCliConfig, saveCliConfig, } from './lib/config-store.js';
3
4
  import { runEvaluationSuite } from './lib/eval.js';
4
5
  import { defaultBaseUrl, defaultMcpServerAlias, defaultMcpUrl, installMcpConfig, removeMcpConfig, resolveMcpConfigPath, } from './lib/mcp-config.js';
5
6
  import { diagnoseMcpConfig, formatMcpDoctorResult } from './lib/doctor.js';
6
7
  import { fetchJson, fetchText, runDoctor } from './lib/http.js';
7
- import { installSkill, removeSkill, resolveSkillInstallTarget, } from './lib/skill.js';
8
+ import { installSkill, removeSkill, resolveSkillInstallTarget, supportedSkillName, } from './lib/skill.js';
8
9
  let cliVersionPromise;
9
10
  async function resolveCliVersion() {
10
11
  if (!cliVersionPromise) {
@@ -83,6 +84,20 @@ function supportedSkillClient(value) {
83
84
  }
84
85
  throw new Error('Skill client phải là codex, cursor, claude-code, antigravity, vscode hoặc opencode.');
85
86
  }
87
+ function resolveSelectedSkillName(parsed) {
88
+ return supportedSkillName(optionString(parsed, 'name') ??
89
+ optionString(parsed, 'skill-name') ??
90
+ optionString(parsed, 'skill'));
91
+ }
92
+ function withSelectedSkillName(parsed, skillName) {
93
+ return {
94
+ ...parsed,
95
+ options: {
96
+ ...parsed.options,
97
+ name: skillName,
98
+ },
99
+ };
100
+ }
86
101
  function defaultSkillClientForMcpClient(client) {
87
102
  switch (client) {
88
103
  case 'codex':
@@ -110,6 +125,13 @@ function supportedScope(value) {
110
125
  }
111
126
  throw new Error('Scope phải là global hoặc project.');
112
127
  }
128
+ function hasExplicitClientSelection(parsed, explicitClient) {
129
+ return Boolean(explicitClient ?? optionString(parsed, 'client') ?? parsed.positionals[2]);
130
+ }
131
+ function resolveScopeForSelectedClient(parsed, defaults, explicitClient) {
132
+ return (supportedScope(optionString(parsed, 'scope')) ??
133
+ (hasExplicitClientSelection(parsed, explicitClient) ? undefined : defaults.defaultScope));
134
+ }
113
135
  async function loadRuntimeDefaults(parsed) {
114
136
  const homeDir = optionString(parsed, 'home-dir');
115
137
  const config = await loadCliConfig(homeDir);
@@ -168,7 +190,7 @@ function resolveSelectedSkillClient(parsed, defaults, client) {
168
190
  }
169
191
  function deriveDefaultsForClient(parsed, defaults, client) {
170
192
  const nextClient = client ?? defaults.defaultClient;
171
- const nextScope = supportedScope(optionString(parsed, 'scope')) ?? defaults.defaultScope;
193
+ const nextScope = resolveScopeForSelectedClient(parsed, defaults);
172
194
  const nextSkillClient = resolveSelectedSkillClient(parsed, defaults, nextClient);
173
195
  return {
174
196
  ...defaults,
@@ -194,7 +216,7 @@ function resolveAuthForMcp(parsed, defaults) {
194
216
  const authToken = validateMcpToken(optionString(parsed, 'mcp-token') ?? defaults.mcpToken);
195
217
  const authEnvVar = optionString(parsed, 'auth-env-var') ?? defaults.authEnvVar;
196
218
  if (!authToken?.trim() && !authEnvVar?.trim()) {
197
- throw new Error('Chưa có token MCP trong config. Hãy chạy sp-rag install --client <client> --mcp-token <token> hoặc sp-rag token add --token <token>.');
219
+ throw new Error('Chưa có token MCP trong config. Hãy chạy sp-rag token add --token <token> một lần, hoặc truyền --mcp-token cho lần cài đặt này.');
198
220
  }
199
221
  return {
200
222
  authToken: authToken?.trim(),
@@ -222,10 +244,12 @@ Lệnh chính:
222
244
  sp-rag codegraph recover [--base-url URL] [--reason TEXT]
223
245
  sp-rag codegraph sync [--base-url URL] [--branch BRANCH] [--commit-sha SHA] [--force] [--webhook-token TOKEN] [--gitlab-job-token TOKEN]
224
246
  sp-rag docs get <public|function|dev> [--base-url URL] [--format md|json|html]
225
- sp-rag mcp add <codex|cursor|claude-code|antigravity|vscode|opencode> [--url URL] [--scope global|project] [--auth-env-var ENV_VAR] [--mcp-token TOKEN]
226
- sp-rag skill install [--client codex|cursor|claude-code|antigravity|vscode|opencode] [--skill-client codex|cursor|claude-code|antigravity|vscode|opencode] [--scope global|project] [--cwd PATH] [--target-dir PATH] [--mcp-url URL] [--docs-url URL]
227
- sp-rag eval run --file eval-suite.json [--base-url URL]
228
- sp-rag update setup [--client codex|cursor|claude-code|antigravity|vscode|opencode] [--skill-client codex|cursor|claude-code|antigravity|vscode|opencode] [--scope global|project] [--url URL] [--auth-env-var ENV_VAR] [--target-dir PATH]
247
+ sp-rag mcp add <codex|cursor|claude-code|antigravity|vscode|opencode> [--url URL] [--scope global|project] [--auth-env-var ENV_VAR] [--mcp-token TOKEN]
248
+ sp-rag skill install [--client codex|cursor|claude-code|antigravity|vscode|opencode] [--skill-client codex|cursor|claude-code|antigravity|vscode|opencode] [--scope global|project] [--cwd PATH] [--target-dir PATH] [--mcp-url URL] [--docs-url URL]
249
+ sp-rag audit install --client codex|cursor|claude-code|antigravity|vscode|opencode [--scope global|project] [--mcp-token TOKEN] [--auth-env-var ENV_VAR] [--target-dir PATH] [--doctor]
250
+ sp-rag audit signal --file signal.json [--mcp-token TOKEN] [--external-ref REF] [--title TEXT] [--provider builtin]
251
+ sp-rag eval run --file eval-suite.json [--base-url URL]
252
+ sp-rag update setup [--client codex|cursor|claude-code|antigravity|vscode|opencode] [--name sp-rag|sp-audit] [--skill-client codex|cursor|claude-code|antigravity|vscode|opencode] [--scope global|project] [--url URL] [--auth-env-var ENV_VAR] [--target-dir PATH]
229
253
  `;
230
254
  }
231
255
  function buildCliConfig(defaults) {
@@ -374,7 +398,7 @@ async function runMcpAdd(parsed, defaults, explicitClient) {
374
398
  const result = await installMcpConfig({
375
399
  client,
376
400
  url: optionString(parsed, 'url') ?? defaults.mcpUrl,
377
- scope: supportedScope(optionString(parsed, 'scope')) ?? defaults.defaultScope,
401
+ scope: resolveScopeForSelectedClient(parsed, defaults, explicitClient),
378
402
  authEnvVar: resolveAuthForMcp(parsed, defaults).authEnvVar,
379
403
  authToken: resolveAuthForMcp(parsed, defaults).authToken,
380
404
  cwd: optionString(parsed, 'cwd'),
@@ -386,6 +410,7 @@ async function runSkillInstall(parsed, defaults, explicitClient) {
386
410
  const client = resolveSelectedSkillClient(parsed, defaults, explicitClient) ?? 'codex';
387
411
  const result = await installSkill({
388
412
  client,
413
+ skillName: resolveSelectedSkillName(parsed),
389
414
  cwd: optionString(parsed, 'cwd'),
390
415
  scope: supportedScope(optionString(parsed, 'scope')),
391
416
  targetDir: optionString(parsed, 'target-dir'),
@@ -415,7 +440,7 @@ async function emitDoctorReport(parsed, defaults, explicitClient, checks) {
415
440
  client,
416
441
  url: defaults.mcpUrl,
417
442
  serverAlias: defaults.serverAlias,
418
- scope: supportedScope(optionString(parsed, 'scope')) ?? defaults.defaultScope,
443
+ scope: resolveScopeForSelectedClient(parsed, defaults, explicitClient),
419
444
  cwd: optionString(parsed, 'cwd'),
420
445
  });
421
446
  for (const line of formatMcpDoctorResult(mcpDiagnostic)) {
@@ -462,7 +487,7 @@ async function runInstall(parsed) {
462
487
  const defaults = await loadRuntimeDefaults(parsed);
463
488
  const client = resolveSelectedClient(parsed, defaults);
464
489
  if (!client) {
465
- throw new Error('Thiếu client. Dùng sp-rag install --client <client> --mcp-token <token>.');
490
+ throw new Error('Thiếu client. Dùng sp-rag install --client <client>.');
466
491
  }
467
492
  await runClientSetup(parsed, defaults, client);
468
493
  }
@@ -474,6 +499,15 @@ async function runAdd(parsed) {
474
499
  }
475
500
  await runClientSetup(parsed, defaults, client);
476
501
  }
502
+ async function runAuditInstall(parsed) {
503
+ const auditParsed = withSelectedSkillName(parsed, 'sp-audit');
504
+ const defaults = await loadRuntimeDefaults(auditParsed);
505
+ const client = resolveSelectedClient(auditParsed, defaults);
506
+ if (!client) {
507
+ throw new Error('Thieu client. Dung sp-rag audit install --client <client>.');
508
+ }
509
+ await runClientSetup(auditParsed, defaults, client);
510
+ }
477
511
  async function runTokenAdd(parsed) {
478
512
  const defaults = await loadRuntimeDefaults(parsed);
479
513
  const token = validateMcpToken(optionString(parsed, 'token') ?? optionString(parsed, 'mcp-token') ?? defaults.mcpToken);
@@ -510,7 +544,7 @@ async function runConfigShow(parsed) {
510
544
  async function runExplain(parsed) {
511
545
  const defaults = await loadRuntimeDefaults(parsed);
512
546
  const client = resolveSelectedClient(parsed, defaults);
513
- const scope = supportedScope(optionString(parsed, 'scope')) ?? defaults.defaultScope;
547
+ const scope = resolveScopeForSelectedClient(parsed, defaults);
514
548
  const tokenStatus = defaults.mcpToken?.trim()
515
549
  ? 'đã lưu'
516
550
  : defaults.authEnvVar?.trim()
@@ -542,6 +576,7 @@ async function runExplain(parsed) {
542
576
  if (skillClient) {
543
577
  const skillTarget = resolveSkillInstallTarget({
544
578
  client: skillClient,
579
+ skillName: resolveSelectedSkillName(parsed),
545
580
  scope: supportedScope(optionString(parsed, 'scope')),
546
581
  cwd: optionString(parsed, 'cwd'),
547
582
  targetDir: optionString(parsed, 'target-dir'),
@@ -560,7 +595,8 @@ async function runExplain(parsed) {
560
595
  lines.push('## Cách dùng chuẩn');
561
596
  if (!defaults.mcpToken?.trim() && !defaults.authEnvVar?.trim()) {
562
597
  lines.push('- Máy này chưa có token MCP. Hãy chạy:');
563
- lines.push(` sp-rag install --client ${client ?? 'vscode'} --mcp-token <token>`);
598
+ lines.push(' sp-rag token add --token <token>');
599
+ lines.push(` sp-rag install --client ${client ?? 'vscode'}`);
564
600
  }
565
601
  else {
566
602
  const chosenClient = client ?? defaults.defaultClient ?? 'vscode';
@@ -589,6 +625,52 @@ async function runEval(parsed) {
589
625
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
590
626
  return result.failed === 0 ? 0 : 1;
591
627
  }
628
+ async function runAuditSignal(parsed) {
629
+ const filePath = optionString(parsed, 'file');
630
+ if (!filePath) {
631
+ throw new Error('Thieu --file tro toi JSON signal cua sp-audit.');
632
+ }
633
+ const defaults = await loadRuntimeDefaults(parsed);
634
+ const token = validateMcpToken(optionString(parsed, 'mcp-token') ?? defaults.mcpToken);
635
+ if (!token?.trim()) {
636
+ throw new Error('Thieu token. Dung --mcp-token <grc_pat_...> hoac sp-rag token add --token <grc_pat_...>.');
637
+ }
638
+ const raw = await readFile(filePath, 'utf8');
639
+ let parsedSignal;
640
+ try {
641
+ parsedSignal = JSON.parse(raw);
642
+ }
643
+ catch {
644
+ parsedSignal = undefined;
645
+ }
646
+ const fileName = optionString(parsed, 'file-name') ?? path.basename(filePath);
647
+ const externalRef = optionString(parsed, 'external-ref') ?? `sp-audit:${fileName}`;
648
+ const titleHint = optionString(parsed, 'title') ??
649
+ (typeof parsedSignal?.['flow'] === 'string'
650
+ ? `SP-AUDIT signal: ${parsedSignal['flow']}`
651
+ : 'SP-AUDIT optimization signal');
652
+ const params = new URLSearchParams({
653
+ external_ref: externalRef,
654
+ file_name: fileName,
655
+ content_type: 'application/json',
656
+ title_hint: titleHint,
657
+ provider: optionString(parsed, 'provider') ?? 'builtin',
658
+ normalizer_provider: 'heuristic',
659
+ warm_cache: 'false',
660
+ });
661
+ const result = await fetchJson(`${defaults.baseUrl.replace(/\/+$/, '')}/api/v1/import/knowledge-source/file?${params.toString()}`, {
662
+ method: 'POST',
663
+ headers: {
664
+ authorization: `Bearer ${token.trim()}`,
665
+ 'content-type': 'application/json',
666
+ },
667
+ body: raw,
668
+ });
669
+ process.stdout.write(`${JSON.stringify({
670
+ ok: true,
671
+ imported: result,
672
+ }, null, 2)}\n`);
673
+ }
592
674
  async function runUpdateSetup(parsed) {
593
675
  const defaults = await loadRuntimeDefaults(parsed);
594
676
  const client = resolveSelectedClient(parsed, defaults);
@@ -616,7 +698,7 @@ async function runUninstall(parsed) {
616
698
  if (!client) {
617
699
  throw new Error('Thiếu client. Dùng sp-rag uninstall --client <client>.');
618
700
  }
619
- const scope = supportedScope(optionString(parsed, 'scope')) ?? defaults.defaultScope;
701
+ const scope = resolveScopeForSelectedClient(parsed, defaults);
620
702
  const mcpResult = await removeMcpConfig({
621
703
  client,
622
704
  url: optionString(parsed, 'url') ?? defaults.mcpUrl,
@@ -741,6 +823,14 @@ export async function runCli(argv) {
741
823
  await runSkillInstall(parsed, defaults);
742
824
  return 0;
743
825
  }
826
+ if (group === 'audit' && action === 'install') {
827
+ await runAuditInstall(parsed);
828
+ return 0;
829
+ }
830
+ if (group === 'audit' && action === 'signal') {
831
+ await runAuditSignal(parsed);
832
+ return 0;
833
+ }
744
834
  if (group === 'eval' && action === 'run') {
745
835
  return runEval(parsed);
746
836
  }
@@ -62,7 +62,16 @@ function parseTomlEntries(raw) {
62
62
  const headersMatch = line.match(/^\[mcp_servers\.(?:"([^"]+)"|([^\].]+))\.headers\]$/);
63
63
  if (headersMatch) {
64
64
  currentAlias = headersMatch[1] || headersMatch[2];
65
- currentSection = 'headers';
65
+ currentSection = 'legacy_headers';
66
+ if (!entries.has(currentAlias)) {
67
+ entries.set(currentAlias, { alias: currentAlias });
68
+ }
69
+ continue;
70
+ }
71
+ const httpHeadersMatch = line.match(/^\[mcp_servers\.(?:"([^"]+)"|([^\].]+))\.http_headers\]$/);
72
+ if (httpHeadersMatch) {
73
+ currentAlias = httpHeadersMatch[1] || httpHeadersMatch[2];
74
+ currentSection = 'http_headers';
66
75
  if (!entries.has(currentAlias)) {
67
76
  entries.set(currentAlias, { alias: currentAlias });
68
77
  }
@@ -89,12 +98,21 @@ function parseTomlEntries(raw) {
89
98
  if (currentSection === 'server' && key === 'url') {
90
99
  entry.endpoint = normalizeEndpoint(value);
91
100
  }
92
- if (currentSection === 'headers') {
101
+ if (currentSection === 'server' && key === 'bearer_token_env_var') {
102
+ entry.bearerTokenEnvVar = value;
103
+ }
104
+ if (currentSection === 'http_headers') {
93
105
  entry.headers = {
94
106
  ...(entry.headers ?? {}),
95
107
  [key]: value,
96
108
  };
97
109
  }
110
+ if (currentSection === 'legacy_headers') {
111
+ entry.legacyHeaders = {
112
+ ...(entry.legacyHeaders ?? {}),
113
+ [key]: value,
114
+ };
115
+ }
98
116
  entries.set(currentAlias, entry);
99
117
  }
100
118
  return [...entries.values()];
@@ -186,6 +204,12 @@ function analyzeAuthorization(headerValue) {
186
204
  likelyOAuthLogin: true,
187
205
  };
188
206
  }
207
+ function analyzeEntryAuthorization(entry) {
208
+ if (entry.bearerTokenEnvVar?.trim()) {
209
+ return analyzeAuthorization(`Bearer \${${entry.bearerTokenEnvVar.trim()}}`);
210
+ }
211
+ return analyzeAuthorization(entry.headers?.Authorization ?? entry.headers?.authorization);
212
+ }
189
213
  function entriesForClient(raw, client) {
190
214
  if (client === 'codex') {
191
215
  return parseTomlEntries(raw);
@@ -233,8 +257,11 @@ export async function diagnoseMcpConfig(options) {
233
257
  ],
234
258
  };
235
259
  }
236
- const authorization = analyzeAuthorization(entry.headers?.Authorization ?? entry.headers?.authorization);
260
+ const authorization = analyzeEntryAuthorization(entry);
237
261
  const issues = [...baseResult.issues];
262
+ if (options.client === 'codex' && entry.legacyHeaders) {
263
+ issues.push('Codex config đang dùng legacy [mcp_servers.<alias>.headers]. Streamable HTTP MCP cần http_headers, env_http_headers hoặc bearer_token_env_var; legacy headers có thể không expose tools.');
264
+ }
238
265
  if (authorization.authorizationState === 'missing') {
239
266
  issues.push('Thiếu Authorization header. IDE rất dễ rơi sang luồng đăng nhập OAuth.');
240
267
  }
@@ -134,28 +134,38 @@ export function upsertCodexConfig(existing, options) {
134
134
  const aliasPattern = escapeRegex(alias);
135
135
  const cleaned = existing
136
136
  .replace(new RegExp(`(?:^|\\n)\\[mcp_servers\\.(?:"${aliasPattern}"|${aliasPattern})\\.headers\\][\\s\\S]*?(?=(?:\\n\\[[^\\n]+\\])|$)`, 'g'), '')
137
+ .replace(new RegExp(`(?:^|\\n)\\[mcp_servers\\.(?:"${aliasPattern}"|${aliasPattern})\\.http_headers\\][\\s\\S]*?(?=(?:\\n\\[[^\\n]+\\])|$)`, 'g'), '')
137
138
  .replace(new RegExp(`(?:^|\\n)\\[mcp_servers\\.(?:"${aliasPattern}"|${aliasPattern})\\][\\s\\S]*?(?=(?:\\n\\[[^\\n]+\\])|$)`, 'g'), '')
138
139
  .trimEnd();
139
140
  const lines = [
140
141
  `[mcp_servers.${quotedTomlKey(alias)}]`,
141
142
  `url = "${options.url}"`,
142
143
  ];
143
- const headers = bearerHeader(options.authToken, options.authEnvVar, 'shell');
144
- if (headers?.Authorization) {
145
- lines.push('', `[mcp_servers.${quotedTomlKey(alias)}.headers]`);
146
- lines.push(`Authorization = "${headers.Authorization.replace(/"/g, '\\"')}"`);
144
+ const literalHeaders = bearerHeader(options.authToken, undefined, 'shell');
145
+ if (literalHeaders?.Authorization) {
146
+ lines.push('', `[mcp_servers.${quotedTomlKey(alias)}.http_headers]`);
147
+ lines.push(`Authorization = "${literalHeaders.Authorization.replace(/"/g, '\\"')}"`);
148
+ }
149
+ else if (options.authEnvVar?.trim()) {
150
+ lines.push(`bearer_token_env_var = "${options.authEnvVar.trim().replace(/"/g, '\\"')}"`);
147
151
  }
148
152
  return `${cleaned ? `${cleaned}\n\n` : ''}${lines.join('\n')}\n`;
149
153
  }
150
- export function removeCodexConfigContent(existing, serverAlias) {
151
- const alias = serverAlias.trim();
152
- const aliasPattern = escapeRegex(alias);
154
+ function removeCodexSubtable(existing, aliasPattern, subtable) {
153
155
  let removed = false;
154
- const withoutHeaders = existing.replace(new RegExp(`(?:^|\\n)\\[mcp_servers\\.(?:"${aliasPattern}"|${aliasPattern})\\.headers\\][\\s\\S]*?(?=(?:\\n\\[[^\\n]+\\])|$)`, 'g'), () => {
156
+ const content = existing.replace(new RegExp(`(?:^|\\n)\\[mcp_servers\\.(?:"${aliasPattern}"|${aliasPattern})\\.${subtable}\\][\\s\\S]*?(?=(?:\\n\\[[^\\n]+\\])|$)`, 'g'), () => {
155
157
  removed = true;
156
158
  return '';
157
159
  });
158
- const cleaned = withoutHeaders.replace(new RegExp(`(?:^|\\n)\\[mcp_servers\\.(?:"${aliasPattern}"|${aliasPattern})\\][\\s\\S]*?(?=(?:\\n\\[[^\\n]+\\])|$)`, 'g'), () => {
160
+ return { content, removed };
161
+ }
162
+ export function removeCodexConfigContent(existing, serverAlias) {
163
+ const alias = serverAlias.trim();
164
+ const aliasPattern = escapeRegex(alias);
165
+ const withoutLegacyHeaders = removeCodexSubtable(existing, aliasPattern, 'headers');
166
+ const withoutHttpHeaders = removeCodexSubtable(withoutLegacyHeaders.content, aliasPattern, 'http_headers');
167
+ let removed = withoutLegacyHeaders.removed || withoutHttpHeaders.removed;
168
+ const cleaned = withoutHttpHeaders.content.replace(new RegExp(`(?:^|\\n)\\[mcp_servers\\.(?:"${aliasPattern}"|${aliasPattern})\\][\\s\\S]*?(?=(?:\\n\\[[^\\n]+\\])|$)`, 'g'), () => {
159
169
  removed = true;
160
170
  return '';
161
171
  });
package/dist/lib/skill.js CHANGED
@@ -8,6 +8,20 @@ const seoBoosterProjectGuard = [
8
8
  `- Nếu basename không phải \`seo-booster\` hoặc \`sb\`, hãy kiểm tra \`git remote get-url origin\` và chỉ gọi SP-RAG khi remote hiện tại là \`${seoBoosterRemoteUrl}\`.`,
9
9
  '- Nếu project hiện tại không khớp hai điều kiện trên, không được gọi SP-RAG và phải nói rõ MCP này chỉ dành cho seo-booster.',
10
10
  ].join('\n');
11
+ const seoBoosterReportGuard = [
12
+ '- Report file paths repo-relative; do not include machine-specific absolute workspace paths in answers.',
13
+ '- Confirm the workspace by repo basename and remote identity, not by printing a local absolute path.',
14
+ '- Do not grade SP-RAG, MCP, GitNexus, or codegraph quality unless the user explicitly asks for platform evaluation.',
15
+ '- Use MCP as supporting evidence for seo-booster; do not make MCP quality the main subject of an app review.',
16
+ '- Final verdict must judge the target seo-booster workflow or implementation.',
17
+ '- If serious bugs, missing retries, weak constraints, or missing tests are found, do not call the app flow reliable just because MCP citations matched source files.',
18
+ '- For user-facing flows, verify frontend entry points by searching route names, controller actions, or request payload keys.',
19
+ '- If the flow reads or writes database tables, open the actual model and migration or schema files.',
20
+ '- Only call MCP evidence stale when it cites a concrete file, symbol, or behavior that conflicts with current source.',
21
+ '- Treat semantic-only MCP entities as context-only evidence, not stale source evidence.',
22
+ '- Every high or medium risk should include repo-relative path, symbol, line range when available, and confidence.',
23
+ '- If external runtime behavior is not directly verified, mark that specific behavior as not verified instead of using it as strong evidence.',
24
+ ].join('\n');
11
25
  function clientLabel(client) {
12
26
  switch (client) {
13
27
  case 'codex':
@@ -38,6 +52,15 @@ function normalizeScope(client, scope) {
38
52
  return 'global';
39
53
  }
40
54
  }
55
+ export function supportedSkillName(value) {
56
+ if (!value) {
57
+ return undefined;
58
+ }
59
+ if (value === 'sp-rag' || value === 'sp-audit') {
60
+ return value;
61
+ }
62
+ throw new Error('Skill name phải là sp-rag hoặc sp-audit.');
63
+ }
41
64
  function requireProjectCwd(client, cwd) {
42
65
  const resolvedCwd = cwd?.trim() ? cwd : process.cwd();
43
66
  if (!resolvedCwd.trim()) {
@@ -45,19 +68,19 @@ function requireProjectCwd(client, cwd) {
45
68
  }
46
69
  return path.resolve(resolvedCwd);
47
70
  }
48
- export function defaultSkillDir(client = 'codex', cwd, scope) {
71
+ export function defaultSkillDir(client = 'codex', cwd, scope, skillName = 'sp-rag') {
49
72
  const normalizedScope = normalizeScope(client, scope);
50
73
  switch (client) {
51
74
  case 'codex':
52
- return path.join(os.homedir(), '.codex', 'skills', 'sp-rag');
75
+ return path.join(os.homedir(), '.codex', 'skills', skillName);
53
76
  case 'claude-code':
54
77
  return normalizedScope === 'project'
55
- ? path.join(requireProjectCwd(client, cwd), '.claude', 'skills', 'sp-rag')
56
- : path.join(os.homedir(), '.claude', 'skills', 'sp-rag');
78
+ ? path.join(requireProjectCwd(client, cwd), '.claude', 'skills', skillName)
79
+ : path.join(os.homedir(), '.claude', 'skills', skillName);
57
80
  case 'antigravity':
58
- return path.join(os.homedir(), '.gemini', 'antigravity', 'skills', 'sp-rag');
81
+ return path.join(os.homedir(), '.gemini', 'antigravity', 'skills', skillName);
59
82
  case 'opencode':
60
- return path.join(os.homedir(), '.config', 'opencode', 'skills', 'sp-rag');
83
+ return path.join(os.homedir(), '.config', 'opencode', 'skills', skillName);
61
84
  case 'cursor':
62
85
  if (normalizedScope !== 'project') {
63
86
  throw new Error('Cursor rule hiện chỉ nên cài ở scope project qua .cursor/rules.');
@@ -72,10 +95,66 @@ export function defaultSkillDir(client = 'codex', cwd, scope) {
72
95
  function renderSkillMarkdown(context) {
73
96
  return `---
74
97
  name: sp-rag
75
- description: Use SP-RAG for seo-booster codebase, feature, domain, rendered-docs, import-inventory, or codegraph freshness work that needs grounded evidence.
98
+ description: Use SP-RAG for seo-booster codebase, feature, domain, rendered-docs, import-inventory, or codegraph freshness work that needs grounded evidence.
99
+ ---
100
+
101
+ # SP-RAG
102
+
103
+ Target client: ${clientLabel(context.client)}
104
+ Default MCP server alias: \`${context.serverAlias}\`
105
+ MCP URL: \`${context.mcpUrl}\`
106
+ Docs URL: \`${context.docsUrl}\`
107
+
108
+ ## When To Use This Skill
109
+
110
+ - Use SP-RAG whenever the request is about seo-booster codebase, features, business workflows, rendered docs, import inventory, or sync state.
111
+ - Use this skill for seo-booster codebase, feature, business workflow, rendered docs, import inventory, and sync-state questions.
112
+ - The operating model is MCP-grounded, workspace-verified.
113
+ - Do not treat MCP as the only source. MCP gives context; current workspace files and git state verify the final answer.
114
+
115
+ ## Intent Routing
116
+
117
+ - 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.
118
+ - 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.
119
+ - For mixed questions: get MCP context, inspect current files, compare both, then answer.
120
+ - For docs questions, use \`get_rendered_docs\` when public, function, or dev docs may already answer the question.
121
+ - 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.
122
+
123
+ ## Workspace Verification
124
+
125
+ 1. Run or mentally account for \`git status --short\` before relying on MCP for current behavior.
126
+ 2. If MCP cites files, inspect the current workspace version of those files when the answer depends on exact code.
127
+ 3. If changed files are related to the question, current workspace files override MCP evidence.
128
+ 4. If MCP and workspace disagree, say the graph may be stale and explain which source you are trusting.
129
+
130
+ ## Expand Evidence
131
+
132
+ - After \`query_context\`, synthesize from \`matched_passages\`, \`top_entities\`, \`top_relations\`, \`citations\`, and \`feature_memory\` diagnostics when present.
133
+ - Treat \`answer_brief\` as a hint only.
134
+ - Do not stop at the first one or two MCP citations for broad feature questions.
135
+ - Expand through related symbols, callers, services, controllers, jobs, routes, models, components, and tests using workspace search when needed.
136
+ - Prefer rendered docs when they answer business behavior, but verify current code before making implementation claims.
137
+
138
+ ## Guardrails
139
+
140
+ ${seoBoosterProjectGuard}
141
+ ${seoBoosterReportGuard}
142
+ - Codex streamable HTTP MCP config must use \`http_headers\`, \`env_http_headers\`, or \`bearer_token_env_var\`; \`[mcp_servers.<alias>.headers]\` is legacy-invalid and will not expose tools.
143
+ - Find root cause before fixing bugs.
144
+ - Use evidence before conclusions; do not claim completion without verification.
145
+ - For behavior changes, write or update tests before implementation when feasible.
146
+ - If evidence may be stale, say so clearly and mention that the graph or docs may need a refresh.
147
+ - Do not trigger sync or import actions unless the user asked for it or the workflow truly requires it.
148
+ - When rendered docs already answer the question, cite or summarize those docs, then check current code if the answer depends on implementation details.
149
+ `;
150
+ }
151
+ function renderSpAuditMarkdown(context) {
152
+ return `---
153
+ name: sp-audit
154
+ description: Use when reviewing seo-booster or SP-RAG audit reports, scoring report quality, extracting optimization signals, or preparing admin-agent feedback loops.
76
155
  ---
77
156
 
78
- # SP-RAG
157
+ # SP-AUDIT
79
158
 
80
159
  Target client: ${clientLabel(context.client)}
81
160
  Default MCP server alias: \`${context.serverAlias}\`
@@ -84,119 +163,243 @@ Docs URL: \`${context.docsUrl}\`
84
163
 
85
164
  ## When To Use This Skill
86
165
 
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.
166
+ - Use this after an AI agent returns an audit or review report for seo-booster.
167
+ - Use it to score the report quality, identify missing verification, and extract optimization signals.
168
+ - Use it when the user asks to audit MCP/RAG-assisted answers, improve prompts, or make the system learn from weak reports.
169
+ - Do not use it as a replacement for the original source audit. This skill audits the audit result.
91
170
 
92
- ## Intent Routing
171
+ ## Hard Boundaries
93
172
 
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.
173
+ ${seoBoosterProjectGuard}
174
+ - Do not grade SP-RAG, MCP, GitNexus, or codegraph quality unless the report explicitly evaluates platform quality.
175
+ - If the report is supposed to audit seo-booster, the final score must judge report quality for seo-booster, not MCP quality.
176
+ - Report file paths must be repo-relative. Do not include machine-specific absolute workspace paths in the final answer.
177
+ - Tra loi bang tieng Viet. Keep code symbols, file paths, route names, and JSON keys unchanged.
99
178
 
100
- ## Workspace Verification
179
+ ## Required Input
101
180
 
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.
181
+ Before scoring, identify:
106
182
 
107
- ## Expand Evidence
183
+ 1. Target workflow or feature under review.
184
+ 2. Claims made by the audit report.
185
+ 3. MCP evidence the report used, if any.
186
+ 4. Workspace source evidence the report verified.
187
+ 5. Bugs, risks, tests, or gaps the report found.
108
188
 
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.
189
+ If the report lacks enough evidence, score it down and say exactly what evidence is missing.
114
190
 
115
- ## Guardrails
191
+ ## Scoring Rubric
116
192
 
117
- ${seoBoosterProjectGuard}
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.
122
- - Do not trigger sync or import actions unless the user asked for it or the workflow truly requires it.
123
- - When rendered docs already answer the question, cite or summarize those docs, then check current code if the answer depends on implementation details.
193
+ Start from 100 and subtract only for concrete gaps:
194
+
195
+ - Target and repo boundary: 10 points.
196
+ - MCP usage and provenance: 10 points.
197
+ - Source coverage across routes, controllers, services, jobs, models, database, frontend, and tests: 25 points.
198
+ - Evidence quality with repo-relative paths, symbols, line ranges when available, and confidence: 20 points.
199
+ - Risk quality with severity, what can go wrong, why current source suggests it, and verification limits: 15 points.
200
+ - No overclaiming, no local absolute paths, and no accidental MCP/platform grading: 10 points.
201
+ - Optimization signal clarity: 10 points.
202
+
203
+ Verdict bands:
204
+
205
+ - 90-100: pass.
206
+ - 70-89: needs optimization.
207
+ - 0-69: fail.
208
+
209
+ ## Required Output
210
+
211
+ Use this exact structure:
212
+
213
+ ## 1. Audit score
214
+ - Score: X/100
215
+ - Verdict: pass | needs optimization | fail
216
+
217
+ ## 2. What the report did well
218
+
219
+ ## 3. Issues in the report
220
+
221
+ ## 4. Required improvements
222
+
223
+ Separate improvements into:
224
+ - Prompt or skill guardrails.
225
+ - MCP retrieval or indexing.
226
+ - Source-inspection checklist.
227
+ - Tests or evaluation cases.
228
+
229
+ ## 5. Optimization signals for server memory
230
+
231
+ Return one compact JSON object:
232
+
233
+ ~~~json
234
+ {
235
+ "target_app": "seo-booster",
236
+ "flow": "short workflow name",
237
+ "score": 0,
238
+ "verdict": "pass | needs_optimization | fail",
239
+ "missing_checks": [],
240
+ "prompt_guardrail_gaps": [],
241
+ "mcp_retrieval_gaps": [],
242
+ "source_index_gaps": [],
243
+ "recommended_actions": [],
244
+ "requires_admin_agent": false
245
+ }
246
+ ~~~
247
+
248
+ ## 6. Admin-agent fallback command
249
+
250
+ If a dedicated server-side audit-signal ingestion endpoint is available, send the JSON signal there and mention the trace/id returned.
251
+
252
+ If server-side self-evolution is not available, do not claim it happened. If token is already saved in \`sp-rag\`, tell the admin to run:
253
+
254
+ \`sp-rag audit install --client <codex|cursor|claude-code|antigravity|vscode|opencode>\`
255
+
256
+ If this is the first setup on the machine, save the token once with:
257
+
258
+ \`sp-rag token add --token <token>\`
259
+
260
+ Then run the audit install command above. The admin AI agent should use the installed \`sp-audit\` skill to review new audit outputs. To persist the JSON signal through the existing server memory import path, save the JSON object and run:
261
+
262
+ \`sp-rag audit signal --file <signal.json>\`
263
+
264
+ Feed the same JSON signal into the next prompt, eval suite, retrieval tuning task, or reviewed server-side memory import.
265
+
266
+ ## Evolution Policy
267
+
268
+ - Self-evolution must be review-gated. Do not let the server silently rewrite prompts, skills, indexes, or production settings from one weak report.
269
+ - If the same optimization signal repeats across reports, propose a durable change: prompt guardrail, skill update, eval case, retrieval query rewrite, docs import, or index refresh.
270
+ - Prefer measurable changes: a failing eval case before prompt/retrieval changes, then a passing eval after the fix.
124
271
  `;
125
272
  }
273
+ function withoutYamlFrontmatter(markdown) {
274
+ if (!markdown.startsWith('---\n')) {
275
+ return markdown;
276
+ }
277
+ const endIndex = markdown.indexOf('\n---\n', 4);
278
+ if (endIndex < 0) {
279
+ return markdown;
280
+ }
281
+ return markdown.slice(endIndex + '\n---\n'.length);
282
+ }
126
283
  function renderCursorRule(context) {
127
284
  return `---
128
285
  description: Use SP-RAG when the request is about this codebase, internal business workflows, rendered docs, import inventory, or codegraph sync status.
129
- globs:
130
- alwaysApply: true
131
- ---
132
-
133
- # SP-RAG
134
-
286
+ globs:
287
+ alwaysApply: true
288
+ ---
289
+
290
+ # SP-RAG
291
+
135
292
  ${seoBoosterProjectGuard}
293
+ ${seoBoosterReportGuard}
136
294
  - Route by intent before choosing tools.
137
295
  - Use the \`${context.serverAlias}\` MCP server first for feature, domain, architecture, workflow, docs, and "what does this do" questions.
138
296
  - 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.
140
- - Use rendered docs from \`${context.docsUrl}\` when documentation already answers the question.
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.
143
- - For freshness or operational questions, check sync status, recent runs, and metrics before assuming the graph is current.
144
- - Only trigger codegraph sync when the user explicitly asks for it or stale evidence is the confirmed blocker.
145
- - If the evidence may be stale, say so clearly.
297
+ - Verify MCP evidence against \`git status --short\` and current workspace files before making implementation claims.
298
+ - Use rendered docs from \`${context.docsUrl}\` when documentation already answers the question.
299
+ - Treat \`answer_brief\` only as a hint. Build the final answer from \`matched_passages\`, \`top_entities\`, \`top_relations\`, and \`citations\`.
300
+ - 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.
301
+ - For freshness or operational questions, check sync status, recent runs, and metrics before assuming the graph is current.
302
+ - Only trigger codegraph sync when the user explicitly asks for it or stale evidence is the confirmed blocker.
303
+ - If the evidence may be stale, say so clearly.
304
+ `;
305
+ }
306
+ function renderSpAuditCursorRule(context) {
307
+ return `---
308
+ description: Use SP-AUDIT when reviewing seo-booster audit reports, scoring report quality, or extracting optimization signals.
309
+ globs:
310
+ alwaysApply: false
311
+ ---
312
+
313
+ ${withoutYamlFrontmatter(renderSpAuditMarkdown(context))}
146
314
  `;
147
315
  }
148
316
  function renderVsCodeAgent(context) {
149
317
  return `---
150
318
  name: SP-RAG
151
- description: Use this custom agent whenever the request is about this codebase, internal business workflows, rendered docs, import inventory, or codegraph sync status.
319
+ description: Use this custom agent whenever the request is about this codebase, internal business workflows, rendered docs, import inventory, or codegraph sync status.
320
+ tools: ['${context.serverAlias}/*']
321
+ ---
322
+
323
+ You are the SP-RAG custom agent for this workspace.
324
+
325
+ Use the \`${context.serverAlias}\` MCP server at \`${context.mcpUrl}\` and the rendered docs URL \`${context.docsUrl}\` as your grounded source of truth.
326
+
327
+ Route by intent before choosing tools. MCP gives the semantic map; the current workspace verifies exact code.
328
+
329
+ ## Recommended Workflow
330
+
331
+ 1. For feature, domain, architecture, workflow, docs, and "what does this do" questions, use \`query_context\` first.
332
+ 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.
333
+ 3. Use \`get_rendered_docs\` when public, function, or dev docs may already answer the question.
334
+ 4. Use \`get_sync_status\`, \`get_sync_runs\`, or \`get_sync_metrics\` for freshness, incident review, or operational debugging.
335
+ 5. After MCP returns, verify important citations against current workspace files if the answer depends on exact implementation.
336
+ 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.
337
+ 7. Trigger codegraph sync only when the user explicitly requests a refresh or stale evidence is the confirmed blocker.
338
+
339
+ ## Guardrails
340
+
341
+ ${seoBoosterProjectGuard}
342
+ ${seoBoosterReportGuard}
343
+ - Prefer MCP-grounded evidence before answering from memory, but current workspace files override MCP evidence when they differ.
344
+ - Treat \`answer_brief\` as a hint. Prefer the richer evidence in \`matched_passages\`, \`top_entities\`, \`top_relations\`, and \`citations\` when writing the final answer.
345
+ - When evidence may be stale, say so clearly and mention that a refresh might be needed.
346
+ - Do not trigger sync or import actions unless the workflow truly requires it.
347
+ - When rendered docs already answer the question, summarize those docs instead of rewriting everything from scratch.
348
+ - Find root cause before fixes, write or update tests for behavior changes when feasible, and verify before claiming completion.
349
+ `;
350
+ }
351
+ function renderSpAuditVsCodeAgent(context) {
352
+ return `---
353
+ name: SP-AUDIT
354
+ description: Use this custom agent to score seo-booster audit reports and extract optimization signals.
152
355
  tools: ['${context.serverAlias}/*']
153
356
  ---
154
357
 
155
- You are the SP-RAG custom agent for this workspace.
358
+ You are the SP-AUDIT custom agent for this workspace.
156
359
 
157
- Use the \`${context.serverAlias}\` MCP server at \`${context.mcpUrl}\` and the rendered docs URL \`${context.docsUrl}\` as your grounded source of truth.
158
-
159
- Route by intent before choosing tools. MCP gives the semantic map; the current workspace verifies exact code.
160
-
161
- ## Recommended Workflow
162
-
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.
165
- 3. Use \`get_rendered_docs\` when public, function, or dev docs may already answer the question.
166
- 4. Use \`get_sync_status\`, \`get_sync_runs\`, or \`get_sync_metrics\` for freshness, incident review, or operational debugging.
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.
170
-
171
- ## Guardrails
360
+ Use the \`${context.serverAlias}\` MCP server only when you need to verify freshness, citations, rendered docs, or retrieval gaps. Your primary job is to audit the audit result.
172
361
 
173
- ${seoBoosterProjectGuard}
174
- - Prefer MCP-grounded evidence before answering from memory, but current workspace files override MCP evidence when they differ.
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.
176
- - When evidence may be stale, say so clearly and mention that a refresh might be needed.
177
- - Do not trigger sync or import actions unless the workflow truly requires it.
178
- - When rendered docs already answer the question, summarize those docs instead of rewriting everything from scratch.
179
- - Find root cause before fixes, write or update tests for behavior changes when feasible, and verify before claiming completion.
362
+ ${withoutYamlFrontmatter(renderSpAuditMarkdown(context))}
180
363
  `;
181
364
  }
182
365
  function renderVsCodeAlwaysOnInstructions(context) {
183
366
  return `# SP-RAG workspace instructions
184
-
367
+
185
368
  ${seoBoosterProjectGuard}
369
+ ${seoBoosterReportGuard}
186
370
  - Route by intent before choosing tools.
187
371
  - Use the \`${context.serverAlias}\` MCP server first for feature, domain, architecture, workflow, docs, and "what does this do" questions.
188
372
  - 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.
190
- - Start with \`healthz\` only when connectivity is uncertain or the session is new.
191
- - When \`query_context\` returns, synthesize the final answer from \`matched_passages\`, \`top_entities\`, \`top_relations\`, and \`citations\`.
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.
194
- - Use \`get_rendered_docs\` when rendered docs can answer the question faster than raw code inspection.
195
- - Only trigger codegraph sync when the user explicitly asks for it or stale graph evidence is the confirmed blocker.
196
- - If MCP and current workspace files disagree, say MCP may be stale and trust the current workspace for implementation details.
373
+ - Verify MCP evidence against current workspace state, including \`git status --short\` and current file contents when implementation details matter.
374
+ - Start with \`healthz\` only when connectivity is uncertain or the session is new.
375
+ - When \`query_context\` returns, synthesize the final answer from \`matched_passages\`, \`top_entities\`, \`top_relations\`, and \`citations\`.
376
+ - Treat \`answer_brief\` as a hint only, not the final answer.
377
+ - Expand beyond the first one or two MCP citations for broad feature questions.
378
+ - Use \`get_rendered_docs\` when rendered docs can answer the question faster than raw code inspection.
379
+ - Only trigger codegraph sync when the user explicitly asks for it or stale graph evidence is the confirmed blocker.
380
+ - If MCP and current workspace files disagree, say MCP may be stale and trust the current workspace for implementation details.
197
381
  `;
198
382
  }
199
383
  function renderSkillArtifact(context) {
384
+ if (context.skillName === 'sp-audit') {
385
+ switch (context.client) {
386
+ case 'cursor':
387
+ return {
388
+ fileName: 'sp-audit.mdc',
389
+ content: renderSpAuditCursorRule(context),
390
+ };
391
+ case 'vscode':
392
+ return {
393
+ fileName: 'sp-audit.agent.md',
394
+ content: renderSpAuditVsCodeAgent(context),
395
+ };
396
+ default:
397
+ return {
398
+ fileName: 'SKILL.md',
399
+ content: renderSpAuditMarkdown(context),
400
+ };
401
+ }
402
+ }
200
403
  switch (context.client) {
201
404
  case 'cursor':
202
405
  return {
@@ -218,6 +421,7 @@ function renderSkillArtifact(context) {
218
421
  function createSkillContext(options = {}, client) {
219
422
  return {
220
423
  client: client ?? options.client ?? 'codex',
424
+ skillName: options.skillName ?? 'sp-rag',
221
425
  serverAlias: options.serverAlias?.trim() || 'sp-rag',
222
426
  mcpUrl: options.mcpUrl?.trim() || 'https://sp-rag.secomapp.com/mcp',
223
427
  docsUrl: options.docsUrl?.trim() || 'https://sp-rag.secomapp.com/codegraph/docs/public?format=md',
@@ -227,6 +431,9 @@ function resolveAdditionalSkillArtifacts(options, resolved, context) {
227
431
  if (resolved.client !== 'vscode') {
228
432
  return [];
229
433
  }
434
+ if (context.skillName !== 'sp-rag') {
435
+ return [];
436
+ }
230
437
  const workspaceRoot = resolved.scope === 'project'
231
438
  ? requireProjectCwd('vscode', options.cwd)
232
439
  : undefined;
@@ -243,7 +450,8 @@ function resolveAdditionalSkillArtifacts(options, resolved, context) {
243
450
  export function resolveSkillInstallTarget(options = {}) {
244
451
  const client = options.client ?? 'codex';
245
452
  const scope = normalizeScope(client, options.scope);
246
- const targetDir = path.resolve(options.targetDir ?? defaultSkillDir(client, options.cwd, scope));
453
+ const skillName = options.skillName ?? 'sp-rag';
454
+ const targetDir = path.resolve(options.targetDir ?? defaultSkillDir(client, options.cwd, scope, skillName));
247
455
  const artifact = renderSkillArtifact(createSkillContext(options, client));
248
456
  return {
249
457
  client,
@@ -289,7 +497,10 @@ async function removeIfSpRagArtifact(filePath) {
289
497
  if (content === null) {
290
498
  return false;
291
499
  }
292
- if (!content.includes('SP-RAG') && !content.includes('sp-rag')) {
500
+ if (!content.includes('SP-RAG') &&
501
+ !content.includes('sp-rag') &&
502
+ !content.includes('SP-AUDIT') &&
503
+ !content.includes('sp-audit')) {
293
504
  return false;
294
505
  }
295
506
  await rm(filePath, { force: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sp-rag",
3
- "version": "0.6.14",
3
+ "version": "0.6.16",
4
4
  "description": "CLI cho setup MCP, codegraph GitNexus và skill của SP-RAG",
5
5
  "type": "module",
6
6
  "files": [