sp-rag 0.6.15 → 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 +13 -7
- package/dist/cli.js +2 -0
- package/dist/lib/doctor.js +30 -3
- package/dist/lib/mcp-config.js +19 -9
- package/dist/lib/skill.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,9 +32,10 @@ CLI để setup nhanh SP-RAG theo hướng dev-friendly:
|
|
|
32
32
|
|
|
33
33
|
## Trạng thái package
|
|
34
34
|
|
|
35
|
-
- package npm public: `sp-rag`
|
|
36
|
-
- version
|
|
37
|
-
-
|
|
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`
|
|
38
39
|
|
|
39
40
|
## Cài từ source trong monorepo
|
|
40
41
|
|
|
@@ -289,10 +290,11 @@ sp-rag uninstall --client codex
|
|
|
289
290
|
|
|
290
291
|
- ping các endpoint `api`, `mcp`, `codegraph`
|
|
291
292
|
- đọc đúng file MCP của client để kiểm:
|
|
292
|
-
- IDE đang nhìn vào file nào
|
|
293
|
-
- server entry nào được match theo alias hoặc theo endpoint
|
|
294
|
-
- `Authorization` đang là token literal, env var hợp lệ, hay đang thiếu
|
|
295
|
-
-
|
|
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 vì legacy `[mcp_servers.<alias>.headers]`
|
|
297
|
+
- khả năng IDE sẽ bật link đăng nhập OAuth
|
|
296
298
|
|
|
297
299
|
Ví dụ:
|
|
298
300
|
|
|
@@ -361,6 +363,10 @@ Day JSON signal do `sp-audit` tao ra vao server memory import path:
|
|
|
361
363
|
sp-rag audit signal --file ./sp-audit-signal.json
|
|
362
364
|
```
|
|
363
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
|
+
|
|
364
370
|
Native paths cua audit workflow:
|
|
365
371
|
|
|
366
372
|
- Codex: `~/.codex/skills/sp-audit/SKILL.md`
|
package/dist/cli.js
CHANGED
|
@@ -655,6 +655,8 @@ async function runAuditSignal(parsed) {
|
|
|
655
655
|
content_type: 'application/json',
|
|
656
656
|
title_hint: titleHint,
|
|
657
657
|
provider: optionString(parsed, 'provider') ?? 'builtin',
|
|
658
|
+
normalizer_provider: 'heuristic',
|
|
659
|
+
warm_cache: 'false',
|
|
658
660
|
});
|
|
659
661
|
const result = await fetchJson(`${defaults.baseUrl.replace(/\/+$/, '')}/api/v1/import/knowledge-source/file?${params.toString()}`, {
|
|
660
662
|
method: 'POST',
|
package/dist/lib/doctor.js
CHANGED
|
@@ -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 = '
|
|
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 === '
|
|
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 =
|
|
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
|
}
|
package/dist/lib/mcp-config.js
CHANGED
|
@@ -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
|
|
144
|
-
if (
|
|
145
|
-
lines.push('', `[mcp_servers.${quotedTomlKey(alias)}.
|
|
146
|
-
lines.push(`Authorization = "${
|
|
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
|
-
|
|
151
|
-
const alias = serverAlias.trim();
|
|
152
|
-
const aliasPattern = escapeRegex(alias);
|
|
154
|
+
function removeCodexSubtable(existing, aliasPattern, subtable) {
|
|
153
155
|
let removed = false;
|
|
154
|
-
const
|
|
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
|
-
|
|
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
|
@@ -139,6 +139,7 @@ Docs URL: \`${context.docsUrl}\`
|
|
|
139
139
|
|
|
140
140
|
${seoBoosterProjectGuard}
|
|
141
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.
|
|
142
143
|
- Find root cause before fixing bugs.
|
|
143
144
|
- Use evidence before conclusions; do not claim completion without verification.
|
|
144
145
|
- For behavior changes, write or update tests before implementation when feasible.
|