recker 1.0.28 → 1.0.29-next.72485b7
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 +28 -1
- package/dist/ai/memory.d.ts +35 -0
- package/dist/ai/memory.js +136 -0
- package/dist/browser/types/ai-client.d.ts +29 -0
- package/dist/browser/types/ai-client.js +1 -0
- package/dist/cli/tui/scroll-buffer.js +4 -4
- package/dist/cli/tui/shell.d.ts +1 -0
- package/dist/cli/tui/shell.js +375 -18
- package/dist/mcp/server.js +15 -0
- package/dist/mcp/tools/scrape.d.ts +3 -0
- package/dist/mcp/tools/scrape.js +156 -0
- package/dist/mcp/tools/security.d.ts +3 -0
- package/dist/mcp/tools/security.js +471 -0
- package/dist/mcp/tools/seo.d.ts +3 -0
- package/dist/mcp/tools/seo.js +427 -0
- package/dist/scrape/index.d.ts +2 -0
- package/dist/scrape/index.js +1 -0
- package/dist/scrape/spider.d.ts +61 -0
- package/dist/scrape/spider.js +250 -0
- package/dist/seo/analyzer.js +27 -0
- package/dist/seo/index.d.ts +3 -1
- package/dist/seo/index.js +1 -0
- package/dist/seo/rules/accessibility.js +620 -54
- package/dist/seo/rules/best-practices.d.ts +2 -0
- package/dist/seo/rules/best-practices.js +188 -0
- package/dist/seo/rules/crawl.d.ts +2 -0
- package/dist/seo/rules/crawl.js +307 -0
- package/dist/seo/rules/cwv.d.ts +2 -0
- package/dist/seo/rules/cwv.js +337 -0
- package/dist/seo/rules/ecommerce.d.ts +2 -0
- package/dist/seo/rules/ecommerce.js +252 -0
- package/dist/seo/rules/i18n.d.ts +2 -0
- package/dist/seo/rules/i18n.js +222 -0
- package/dist/seo/rules/index.d.ts +32 -0
- package/dist/seo/rules/index.js +71 -0
- package/dist/seo/rules/internal-linking.d.ts +2 -0
- package/dist/seo/rules/internal-linking.js +375 -0
- package/dist/seo/rules/local.d.ts +2 -0
- package/dist/seo/rules/local.js +265 -0
- package/dist/seo/rules/pwa.d.ts +2 -0
- package/dist/seo/rules/pwa.js +302 -0
- package/dist/seo/rules/readability.d.ts +2 -0
- package/dist/seo/rules/readability.js +255 -0
- package/dist/seo/rules/security.js +406 -28
- package/dist/seo/rules/social.d.ts +2 -0
- package/dist/seo/rules/social.js +373 -0
- package/dist/seo/rules/types.d.ts +155 -0
- package/dist/seo/seo-spider.d.ts +47 -0
- package/dist/seo/seo-spider.js +362 -0
- package/dist/seo/types.d.ts +24 -0
- package/dist/types/ai-client.d.ts +29 -0
- package/dist/types/ai-client.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -109,6 +109,8 @@ See [Mini Client documentation](./docs/http/18-mini-client.md) for more.
|
|
|
109
109
|
| **Type-Safe** | Full TypeScript with Zod schema validation. |
|
|
110
110
|
| **Observable** | DNS/TCP/TLS/TTFB timing breakdown per request. |
|
|
111
111
|
| **Resilient** | Retry, circuit breaker, rate limiting, deduplication. |
|
|
112
|
+
| **SEO Analysis** | 250+ rules across 21 categories. Site-wide crawling with duplicate detection. |
|
|
113
|
+
| **Spider Crawler** | Web crawler with URL deduplication, depth control, and concurrency. |
|
|
112
114
|
| **GeoIP (Offline)** | MaxMind GeoLite2 database with bogon detection. |
|
|
113
115
|
| **RDAP Support** | Modern WHOIS with IANA Bootstrap and TLD detection. |
|
|
114
116
|
|
|
@@ -133,11 +135,31 @@ console.log(response.timings);
|
|
|
133
135
|
// { dns: 12, tcp: 8, tls: 45, firstByte: 23, total: 156 }
|
|
134
136
|
```
|
|
135
137
|
|
|
136
|
-
### Scraping
|
|
138
|
+
### Scraping & Spider
|
|
137
139
|
|
|
138
140
|
```typescript
|
|
141
|
+
// Scrape single page
|
|
139
142
|
const doc = await client.scrape('https://example.com');
|
|
140
143
|
const titles = doc.selectAll('h1').map(el => el.text());
|
|
144
|
+
|
|
145
|
+
// Crawl entire site
|
|
146
|
+
import { spider } from 'recker/scrape';
|
|
147
|
+
const result = await spider('https://example.com', { maxPages: 50 });
|
|
148
|
+
console.log(`Crawled ${result.pages.length} pages`);
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### SEO Analysis
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { analyzeSeo, seoSpider } from 'recker/seo';
|
|
155
|
+
|
|
156
|
+
// Single page analysis - 250+ checks across 21 categories
|
|
157
|
+
const report = await analyzeSeo(html, { baseUrl: 'https://example.com' });
|
|
158
|
+
console.log(`Score: ${report.score}/100 (${report.grade})`);
|
|
159
|
+
|
|
160
|
+
// Site-wide analysis - detect duplicates and orphan pages
|
|
161
|
+
const siteReport = await seoSpider('https://example.com', { seo: true });
|
|
162
|
+
console.log(`Duplicate titles: ${siteReport.summary.duplicateTitles}`);
|
|
141
163
|
```
|
|
142
164
|
|
|
143
165
|
### Circuit Breaker
|
|
@@ -174,6 +196,9 @@ rek -o data.json api.com/export
|
|
|
174
196
|
# Interactive shell
|
|
175
197
|
rek shell
|
|
176
198
|
|
|
199
|
+
# SEO analysis
|
|
200
|
+
rek seo https://example.com
|
|
201
|
+
|
|
177
202
|
# Mock servers for testing
|
|
178
203
|
rek serve http # HTTP on :3000
|
|
179
204
|
rek serve ws # WebSocket on :8080
|
|
@@ -187,6 +212,8 @@ See [CLI Documentation](./docs/cli/01-overview.md) for more.
|
|
|
187
212
|
- **[Quick Start](./docs/http/01-quickstart.md)** - Get running in 2 minutes
|
|
188
213
|
- **[Mini Client](./docs/http/18-mini-client.md)** - Maximum performance mode
|
|
189
214
|
- **[CLI Guide](./docs/cli/01-overview.md)** - Terminal client documentation
|
|
215
|
+
- **[SEO Analysis](./docs/http/19-seo.md)** - 250+ rules, site-wide crawling
|
|
216
|
+
- **[Web Scraping](./docs/http/14-scraping.md)** - HTML parsing and Spider crawler
|
|
190
217
|
- **[API Reference](./docs/reference/01-api.md)** - Complete API documentation
|
|
191
218
|
- **[Configuration](./docs/http/05-configuration.md)** - Client options
|
|
192
219
|
- **[Plugins](./docs/http/10-plugins.md)** - Extend functionality
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ChatMessage } from '../types/ai.js';
|
|
2
|
+
import type { AIMemoryConfig } from '../types/ai-client.js';
|
|
3
|
+
export declare class ConversationMemory {
|
|
4
|
+
private config;
|
|
5
|
+
private systemMessage;
|
|
6
|
+
private messages;
|
|
7
|
+
constructor(config?: AIMemoryConfig);
|
|
8
|
+
setSystemPrompt(prompt: string): void;
|
|
9
|
+
getSystemPrompt(): string;
|
|
10
|
+
addUserMessage(content: string): void;
|
|
11
|
+
addAssistantMessage(content: string): void;
|
|
12
|
+
addMessage(message: ChatMessage): void;
|
|
13
|
+
buildMessages(userPrompt: string): ChatMessage[];
|
|
14
|
+
recordResponse(content: string): void;
|
|
15
|
+
getMessages(): ChatMessage[];
|
|
16
|
+
getConversation(): readonly ChatMessage[];
|
|
17
|
+
getPairCount(): number;
|
|
18
|
+
clear(): void;
|
|
19
|
+
reset(): void;
|
|
20
|
+
setConfig(config: Partial<AIMemoryConfig>): void;
|
|
21
|
+
getConfig(): AIMemoryConfig;
|
|
22
|
+
private prune;
|
|
23
|
+
isEmpty(): boolean;
|
|
24
|
+
getMessageCount(): number;
|
|
25
|
+
toJSON(): {
|
|
26
|
+
config: AIMemoryConfig;
|
|
27
|
+
systemPrompt: string | null;
|
|
28
|
+
messages: ChatMessage[];
|
|
29
|
+
};
|
|
30
|
+
static fromJSON(data: {
|
|
31
|
+
config?: AIMemoryConfig;
|
|
32
|
+
systemPrompt?: string | null;
|
|
33
|
+
messages?: ChatMessage[];
|
|
34
|
+
}): ConversationMemory;
|
|
35
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
const DEFAULT_MAX_PAIRS = 12;
|
|
2
|
+
export class ConversationMemory {
|
|
3
|
+
config;
|
|
4
|
+
systemMessage = null;
|
|
5
|
+
messages = [];
|
|
6
|
+
constructor(config = {}) {
|
|
7
|
+
this.config = {
|
|
8
|
+
maxPairs: config.maxPairs ?? DEFAULT_MAX_PAIRS,
|
|
9
|
+
systemPrompt: config.systemPrompt ?? '',
|
|
10
|
+
};
|
|
11
|
+
if (this.config.systemPrompt) {
|
|
12
|
+
this.systemMessage = {
|
|
13
|
+
role: 'system',
|
|
14
|
+
content: this.config.systemPrompt,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
setSystemPrompt(prompt) {
|
|
19
|
+
this.config.systemPrompt = prompt;
|
|
20
|
+
if (prompt) {
|
|
21
|
+
this.systemMessage = {
|
|
22
|
+
role: 'system',
|
|
23
|
+
content: prompt,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
this.systemMessage = null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
getSystemPrompt() {
|
|
31
|
+
return this.config.systemPrompt;
|
|
32
|
+
}
|
|
33
|
+
addUserMessage(content) {
|
|
34
|
+
this.messages.push({
|
|
35
|
+
role: 'user',
|
|
36
|
+
content,
|
|
37
|
+
});
|
|
38
|
+
this.prune();
|
|
39
|
+
}
|
|
40
|
+
addAssistantMessage(content) {
|
|
41
|
+
this.messages.push({
|
|
42
|
+
role: 'assistant',
|
|
43
|
+
content,
|
|
44
|
+
});
|
|
45
|
+
this.prune();
|
|
46
|
+
}
|
|
47
|
+
addMessage(message) {
|
|
48
|
+
if (message.role === 'system') {
|
|
49
|
+
this.setSystemPrompt(typeof message.content === 'string' ? message.content : '');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this.messages.push(message);
|
|
53
|
+
this.prune();
|
|
54
|
+
}
|
|
55
|
+
buildMessages(userPrompt) {
|
|
56
|
+
this.addUserMessage(userPrompt);
|
|
57
|
+
return this.getMessages();
|
|
58
|
+
}
|
|
59
|
+
recordResponse(content) {
|
|
60
|
+
this.addAssistantMessage(content);
|
|
61
|
+
}
|
|
62
|
+
getMessages() {
|
|
63
|
+
const result = [];
|
|
64
|
+
if (this.systemMessage) {
|
|
65
|
+
result.push(this.systemMessage);
|
|
66
|
+
}
|
|
67
|
+
result.push(...this.messages);
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
getConversation() {
|
|
71
|
+
return this.messages;
|
|
72
|
+
}
|
|
73
|
+
getPairCount() {
|
|
74
|
+
let pairs = 0;
|
|
75
|
+
for (let i = 0; i < this.messages.length - 1; i += 2) {
|
|
76
|
+
if (this.messages[i].role === 'user' &&
|
|
77
|
+
this.messages[i + 1]?.role === 'assistant') {
|
|
78
|
+
pairs++;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return pairs;
|
|
82
|
+
}
|
|
83
|
+
clear() {
|
|
84
|
+
this.messages = [];
|
|
85
|
+
}
|
|
86
|
+
reset() {
|
|
87
|
+
this.messages = [];
|
|
88
|
+
this.systemMessage = null;
|
|
89
|
+
this.config.systemPrompt = '';
|
|
90
|
+
}
|
|
91
|
+
setConfig(config) {
|
|
92
|
+
if (config.maxPairs !== undefined) {
|
|
93
|
+
this.config.maxPairs = config.maxPairs;
|
|
94
|
+
this.prune();
|
|
95
|
+
}
|
|
96
|
+
if (config.systemPrompt !== undefined) {
|
|
97
|
+
this.setSystemPrompt(config.systemPrompt);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
getConfig() {
|
|
101
|
+
return { ...this.config };
|
|
102
|
+
}
|
|
103
|
+
prune() {
|
|
104
|
+
const maxMessages = this.config.maxPairs * 2;
|
|
105
|
+
if (this.messages.length > maxMessages) {
|
|
106
|
+
const excess = this.messages.length - maxMessages;
|
|
107
|
+
const toRemove = Math.ceil(excess / 2) * 2;
|
|
108
|
+
this.messages = this.messages.slice(toRemove);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
isEmpty() {
|
|
112
|
+
return this.messages.length === 0;
|
|
113
|
+
}
|
|
114
|
+
getMessageCount() {
|
|
115
|
+
return this.messages.length;
|
|
116
|
+
}
|
|
117
|
+
toJSON() {
|
|
118
|
+
return {
|
|
119
|
+
config: this.config,
|
|
120
|
+
systemPrompt: this.systemMessage?.content,
|
|
121
|
+
messages: [...this.messages],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
static fromJSON(data) {
|
|
125
|
+
const memory = new ConversationMemory(data.config);
|
|
126
|
+
if (data.systemPrompt) {
|
|
127
|
+
memory.setSystemPrompt(data.systemPrompt);
|
|
128
|
+
}
|
|
129
|
+
if (data.messages) {
|
|
130
|
+
for (const msg of data.messages) {
|
|
131
|
+
memory.addMessage(msg);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return memory;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { AIResponse, AIStream, ChatMessage, AIProvider } from './ai.js';
|
|
2
|
+
export interface AIMemoryConfig {
|
|
3
|
+
maxPairs?: number;
|
|
4
|
+
systemPrompt?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface PresetAIConfig {
|
|
7
|
+
provider: AIProvider;
|
|
8
|
+
apiKey?: string;
|
|
9
|
+
model: string;
|
|
10
|
+
baseUrl?: string;
|
|
11
|
+
memory?: AIMemoryConfig;
|
|
12
|
+
organization?: string;
|
|
13
|
+
headers?: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
export interface ClientAI {
|
|
16
|
+
chat(prompt: string): Promise<AIResponse>;
|
|
17
|
+
chatStream(prompt: string): Promise<AIStream>;
|
|
18
|
+
prompt(prompt: string): Promise<AIResponse>;
|
|
19
|
+
promptStream(prompt: string): Promise<AIStream>;
|
|
20
|
+
clearMemory(): void;
|
|
21
|
+
getMemory(): readonly ChatMessage[];
|
|
22
|
+
setMemoryConfig(config: Partial<AIMemoryConfig>): void;
|
|
23
|
+
getMemoryConfig(): AIMemoryConfig;
|
|
24
|
+
readonly provider: AIProvider;
|
|
25
|
+
readonly model: string;
|
|
26
|
+
}
|
|
27
|
+
export interface ClientOptionsWithAI {
|
|
28
|
+
_aiConfig?: PresetAIConfig;
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -119,17 +119,17 @@ export class ScrollBuffer extends EventEmitter {
|
|
|
119
119
|
}
|
|
120
120
|
export function parseScrollKey(data) {
|
|
121
121
|
const str = data.toString();
|
|
122
|
-
if (str === '\x1b[5~' || str === '\x1bOy')
|
|
122
|
+
if (str === '\x1b[5~' || str === '\x1bOy' || str === '\x1b[5;5~' || str === '\x1b[5;2~')
|
|
123
123
|
return 'pageUp';
|
|
124
|
-
if (str === '\x1b[6~' || str === '\x1bOs')
|
|
124
|
+
if (str === '\x1b[6~' || str === '\x1bOs' || str === '\x1b[6;5~' || str === '\x1b[6;2~')
|
|
125
125
|
return 'pageDown';
|
|
126
126
|
if (str === '\x1b[1;2A')
|
|
127
127
|
return 'scrollUp';
|
|
128
128
|
if (str === '\x1b[1;2B')
|
|
129
129
|
return 'scrollDown';
|
|
130
|
-
if (str === '\x1b[H' || str === '\x1b[1~' || str === '\x1bOH')
|
|
130
|
+
if (str === '\x1b[H' || str === '\x1b[1~' || str === '\x1bOH' || str === '\x1b[7~')
|
|
131
131
|
return 'home';
|
|
132
|
-
if (str === '\x1b[F' || str === '\x1b[4~' || str === '\x1bOF')
|
|
132
|
+
if (str === '\x1b[F' || str === '\x1b[4~' || str === '\x1bOF' || str === '\x1b[8~')
|
|
133
133
|
return 'end';
|
|
134
134
|
if (str === 'q' || str === 'Q')
|
|
135
135
|
return 'quit';
|