clippy-test 1.0.8 → 2.0.0
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/LICENSE +21 -0
- package/README.md +172 -0
- package/bin/oncall.js +396 -0
- package/dist/api.js +10 -1
- package/dist/cli.js +20 -20
- package/dist/config.js +7 -7
- package/dist/helpers/cli-helpers.d.ts +25 -0
- package/dist/helpers/cli-helpers.js +329 -0
- package/dist/helpers/config-helpers.js +189 -0
- package/dist/helpers/ripgrep-tool.d.ts +15 -0
- package/dist/helpers/ripgrep-tool.js +126 -0
- package/dist/index.js +318 -122
- package/dist/logsManager.d.ts +31 -0
- package/dist/logsManager.js +90 -0
- package/dist/postinstall.js +20 -0
- package/dist/tools/ripgrep.d.ts +15 -0
- package/dist/tools/ripgrep.js +110 -0
- package/dist/useWebSocket.d.ts +14 -7
- package/dist/useWebSocket.js +291 -48
- package/dist/utils/version-check.d.ts +2 -0
- package/dist/utils/version-check.js +124 -0
- package/dist/utils.d.ts +16 -0
- package/dist/utils.js +125 -4
- package/dist/websocket-server.d.ts +24 -0
- package/dist/websocket-server.js +235 -0
- package/package.json +19 -6
- package/bin/clippy.js +0 -109
- package/dist/api.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/code_hierarchy.js.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/ui-graph.js.map +0 -1
- package/dist/useWebSocket.js.map +0 -1
- package/dist/utils.js.map +0 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Singleton Logs Manager
|
|
3
|
+
* Maintains logs data
|
|
4
|
+
*/
|
|
5
|
+
export declare class LogsManager {
|
|
6
|
+
private static instance;
|
|
7
|
+
private logs;
|
|
8
|
+
private constructor();
|
|
9
|
+
/**
|
|
10
|
+
* Get the singleton instance
|
|
11
|
+
*/
|
|
12
|
+
static getInstance(): LogsManager;
|
|
13
|
+
/**
|
|
14
|
+
* Append Logs
|
|
15
|
+
* @param chunk
|
|
16
|
+
*/
|
|
17
|
+
addChunk(chunk: string): void;
|
|
18
|
+
/**
|
|
19
|
+
* Retrieves logs
|
|
20
|
+
*/
|
|
21
|
+
getLogs(): string;
|
|
22
|
+
getTailLogs(n: number): string;
|
|
23
|
+
getGrepLogs(pattern: string, before?: number, after?: number): string;
|
|
24
|
+
getRecentErrors(n: number): string;
|
|
25
|
+
/**
|
|
26
|
+
* Clear all logs
|
|
27
|
+
*/
|
|
28
|
+
clearAll(): void;
|
|
29
|
+
}
|
|
30
|
+
declare const _default: LogsManager;
|
|
31
|
+
export default _default;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Singleton Logs Manager
|
|
3
|
+
* Maintains logs data
|
|
4
|
+
*/
|
|
5
|
+
export class LogsManager {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.logs = "";
|
|
8
|
+
// Private constructor to prevent direct instantiation
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Get the singleton instance
|
|
12
|
+
*/
|
|
13
|
+
static getInstance() {
|
|
14
|
+
if (!LogsManager.instance) {
|
|
15
|
+
LogsManager.instance = new LogsManager();
|
|
16
|
+
}
|
|
17
|
+
return LogsManager.instance;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Append Logs
|
|
21
|
+
* @param chunk
|
|
22
|
+
*/
|
|
23
|
+
addChunk(chunk) {
|
|
24
|
+
this.logs += chunk;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Retrieves logs
|
|
28
|
+
*/
|
|
29
|
+
getLogs() {
|
|
30
|
+
return this.logs;
|
|
31
|
+
}
|
|
32
|
+
getTailLogs(n) {
|
|
33
|
+
const logs = this.getLogs() || "";
|
|
34
|
+
const linesArr = logs.split("\n");
|
|
35
|
+
const tail = linesArr.slice(-n).join("\n");
|
|
36
|
+
return tail;
|
|
37
|
+
}
|
|
38
|
+
getGrepLogs(pattern, before = 5, after = 5) {
|
|
39
|
+
const logs = this.getLogs() || "";
|
|
40
|
+
if (!pattern || !pattern.trim()) {
|
|
41
|
+
return "";
|
|
42
|
+
}
|
|
43
|
+
const lines = logs.split("\n");
|
|
44
|
+
const normalizedPattern = pattern.toLowerCase();
|
|
45
|
+
const beforeCount = before;
|
|
46
|
+
const afterCount = after;
|
|
47
|
+
const blocks = [];
|
|
48
|
+
for (let i = 0; i < lines.length; i++) {
|
|
49
|
+
const line = lines[i];
|
|
50
|
+
if (line.toLowerCase().includes(normalizedPattern)) {
|
|
51
|
+
const start = Math.max(0, i - beforeCount);
|
|
52
|
+
const end = Math.min(lines.length, i + afterCount + 1);
|
|
53
|
+
const contextBlock = lines.slice(start, end).join("\n");
|
|
54
|
+
blocks.push(`block (match line ${i + 1}): ${contextBlock}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (blocks.length === 0) {
|
|
58
|
+
return `No matches found for pattern "${pattern}" in logs.`;
|
|
59
|
+
}
|
|
60
|
+
return blocks.join("\n\n");
|
|
61
|
+
}
|
|
62
|
+
getRecentErrors(n) {
|
|
63
|
+
const logs = this.getLogs() || "";
|
|
64
|
+
const lines = logs.split("\n");
|
|
65
|
+
const matched = [];
|
|
66
|
+
if (!Number.isFinite(n) || n <= 0) {
|
|
67
|
+
return "Invalid value for n. Please provide a positive number of error lines to fetch.";
|
|
68
|
+
}
|
|
69
|
+
const errorRegex = /\b(ERROR|ERR|FATAL|CRITICAL|WARN|WARNING|SEVERE|ALERT|PANIC|EMERGENCY)\b|(Exception|Unhandled|Uncaught|Traceback|stacktrace|Caused by:)|(TypeError|ReferenceError|RangeError|SyntaxError|RuntimeError|ValueError|NullPointerException|IllegalArgument)|(timeout|timed out|connection refused|connection reset|ECONNRESET|ECONNREFUSED|ETIMEDOUT|EAI_AGAIN)|(HTTP\s(4\d\d|5\d\d)|\b5\d\d\b|\b429\b|\b503\b)|(OOM|out of memory|disk full|quota exceeded|rate limited|deadlock|segfault|SIGKILL|panic)/i;
|
|
70
|
+
for (let i = lines.length - 1; i >= 0 && matched.length < n; i--) {
|
|
71
|
+
const line = lines[i];
|
|
72
|
+
if (errorRegex.test(line)) {
|
|
73
|
+
matched.push(line);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (matched.length === 0) {
|
|
77
|
+
return "No recent error log lines found";
|
|
78
|
+
}
|
|
79
|
+
return matched.reverse().join("\n");
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Clear all logs
|
|
83
|
+
*/
|
|
84
|
+
clearAll() {
|
|
85
|
+
this.logs = "";
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Export the singleton instance
|
|
89
|
+
export default LogsManager.getInstance();
|
|
90
|
+
//# sourceMappingURL=logsManager.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
|
|
5
|
+
try {
|
|
6
|
+
const patchPackagePath = join(process.cwd(), 'node_modules', '.bin', 'patch-package');
|
|
7
|
+
const patchesDir = join(process.cwd(), 'patches');
|
|
8
|
+
|
|
9
|
+
if (existsSync(patchPackagePath) && existsSync(patchesDir)) {
|
|
10
|
+
execSync('patch-package', { stdio: 'ignore', timeout: 5000 });
|
|
11
|
+
}
|
|
12
|
+
} catch (error) {
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
console.log(`
|
|
16
|
+
OnCall installed.
|
|
17
|
+
|
|
18
|
+
Run:
|
|
19
|
+
oncall --help
|
|
20
|
+
to get started.`);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface RipgrepResult {
|
|
2
|
+
filePath: string;
|
|
3
|
+
line?: number | null;
|
|
4
|
+
preview?: string;
|
|
5
|
+
score?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface RipgrepOptions {
|
|
8
|
+
maxResults?: number;
|
|
9
|
+
caseSensitive?: boolean;
|
|
10
|
+
fileTypes?: string[];
|
|
11
|
+
excludePatterns?: string[];
|
|
12
|
+
workingDirectory?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function ripgrepSearch(query: string, options?: RipgrepOptions): Promise<RipgrepResult[]>;
|
|
15
|
+
export declare function ripgrepSearchMultiple(queries: string[], options?: RipgrepOptions): Promise<RipgrepResult[]>;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { RipGrep } from "ripgrep-node";
|
|
2
|
+
export async function ripgrepSearch(query, options = {}) {
|
|
3
|
+
const defaultExcludePatterns = [
|
|
4
|
+
"node_modules",
|
|
5
|
+
".git",
|
|
6
|
+
"dist",
|
|
7
|
+
"build",
|
|
8
|
+
".next",
|
|
9
|
+
".cache",
|
|
10
|
+
"coverage",
|
|
11
|
+
".nyc_output",
|
|
12
|
+
".vscode",
|
|
13
|
+
".idea",
|
|
14
|
+
"*.log",
|
|
15
|
+
"*.lock",
|
|
16
|
+
"package-lock.json",
|
|
17
|
+
"yarn.lock",
|
|
18
|
+
"pnpm-lock.yaml",
|
|
19
|
+
".env",
|
|
20
|
+
".env.*",
|
|
21
|
+
"*.min.js",
|
|
22
|
+
"*.min.css",
|
|
23
|
+
".DS_Store",
|
|
24
|
+
"Thumbs.db",
|
|
25
|
+
];
|
|
26
|
+
const { maxResults = 20, caseSensitive = false, fileTypes = [], excludePatterns = defaultExcludePatterns, workingDirectory, } = options;
|
|
27
|
+
if (!query || query.trim().length === 0) {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
const searchDir = workingDirectory || (typeof process !== "undefined" ? process.cwd() : undefined);
|
|
31
|
+
if (!searchDir) {
|
|
32
|
+
// console.error("[ripgrep] workingDirectory is required for client-side usage");
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
let rg = new RipGrep(query, searchDir);
|
|
37
|
+
rg.withFilename().lineNumber();
|
|
38
|
+
if (!caseSensitive) {
|
|
39
|
+
rg.ignoreCase();
|
|
40
|
+
}
|
|
41
|
+
if (fileTypes.length > 0) {
|
|
42
|
+
for (const ext of fileTypes) {
|
|
43
|
+
rg.glob(`*.${ext}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
for (const pattern of excludePatterns) {
|
|
47
|
+
const hasFileExtension = /\.(json|lock|yaml|js|css|log)$/.test(pattern) ||
|
|
48
|
+
pattern.startsWith("*.") ||
|
|
49
|
+
pattern === ".env" ||
|
|
50
|
+
pattern.startsWith(".env.") ||
|
|
51
|
+
pattern === ".DS_Store" ||
|
|
52
|
+
pattern === "Thumbs.db";
|
|
53
|
+
const isFilePattern = pattern.includes("*") || hasFileExtension;
|
|
54
|
+
const excludePattern = isFilePattern ? `!${pattern}` : `!${pattern}/**`;
|
|
55
|
+
rg.glob(excludePattern);
|
|
56
|
+
}
|
|
57
|
+
const output = await rg.run().asString();
|
|
58
|
+
if (!output || output.trim().length === 0) {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
const lines = output.trim().split("\n");
|
|
62
|
+
const results = [];
|
|
63
|
+
for (const line of lines.slice(0, maxResults)) {
|
|
64
|
+
const match = line.match(/^(.+?):(\d+):(.+)$/);
|
|
65
|
+
if (match) {
|
|
66
|
+
const [, filePath, lineNum, content] = match;
|
|
67
|
+
const lineNumber = lineNum ? parseInt(lineNum, 10) : null;
|
|
68
|
+
const preview = content ? content.trim().slice(0, 200) : undefined;
|
|
69
|
+
results.push({
|
|
70
|
+
filePath: filePath.trim(),
|
|
71
|
+
line: lineNumber ?? null,
|
|
72
|
+
preview: preview || undefined,
|
|
73
|
+
score: 1.0,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return results;
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
if (error.message?.includes("No matches") ||
|
|
81
|
+
error.message?.includes("not found") ||
|
|
82
|
+
error.code === 1) {
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
// console.error("[ripgrep] Error executing ripgrep:", error.message);
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export async function ripgrepSearchMultiple(queries, options = {}) {
|
|
90
|
+
const allResults = [];
|
|
91
|
+
for (const query of queries) {
|
|
92
|
+
const results = await ripgrepSearch(query, {
|
|
93
|
+
...options,
|
|
94
|
+
maxResults: Math.ceil((options.maxResults || 20) / queries.length),
|
|
95
|
+
});
|
|
96
|
+
allResults.push(...results);
|
|
97
|
+
}
|
|
98
|
+
// Deduplicate by filePath:line
|
|
99
|
+
const seen = new Set();
|
|
100
|
+
const unique = [];
|
|
101
|
+
for (const result of allResults) {
|
|
102
|
+
const key = `${result.filePath}:${result.line}`;
|
|
103
|
+
if (!seen.has(key)) {
|
|
104
|
+
seen.add(key);
|
|
105
|
+
unique.push(result);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return unique.slice(0, options.maxResults || 20);
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=ripgrep.js.map
|
package/dist/useWebSocket.d.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
import WebSocket from "ws";
|
|
2
|
+
import { BaseMessage } from "langchain";
|
|
3
|
+
import { LogsManager } from "./logsManager.js";
|
|
4
|
+
export declare function useWebSocket(url: string, rawLogData: LogsManager): {
|
|
2
5
|
connectWebSocket: () => void;
|
|
3
6
|
socketId: string;
|
|
4
|
-
sendQuery: (
|
|
5
|
-
chatResponseMessages:
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
sendQuery: (messages: BaseMessage[], architecture: string, logs?: string, planningDoc?: string) => void;
|
|
8
|
+
chatResponseMessages: BaseMessage<import("@langchain/core/messages").MessageStructure, import("@langchain/core/messages").MessageType>[];
|
|
9
|
+
visibleChats: BaseMessage<import("@langchain/core/messages").MessageStructure, import("@langchain/core/messages").MessageType>[];
|
|
10
|
+
setVisibleChats: import("react").Dispatch<import("react").SetStateAction<BaseMessage<import("@langchain/core/messages").MessageStructure, import("@langchain/core/messages").MessageType>[]>>;
|
|
11
|
+
setChatResponseMessages: import("react").Dispatch<import("react").SetStateAction<BaseMessage<import("@langchain/core/messages").MessageStructure, import("@langchain/core/messages").MessageType>[]>>;
|
|
12
|
+
setTrimmedChats: import("react").Dispatch<import("react").SetStateAction<BaseMessage<import("@langchain/core/messages").MessageStructure, import("@langchain/core/messages").MessageType>[]>>;
|
|
8
13
|
isConnected: boolean;
|
|
9
14
|
connectionError: string;
|
|
10
15
|
isLoading: boolean;
|
|
@@ -13,8 +18,10 @@ export declare function useWebSocket(url: string): {
|
|
|
13
18
|
setIsConnected: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
14
19
|
socket: WebSocket;
|
|
15
20
|
setIsLoading: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
16
|
-
setIsControlRPressed: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
17
21
|
setShowControlR: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
18
22
|
showControlR: boolean;
|
|
19
|
-
setCompleteChatHistory: import("react").Dispatch<import("react").SetStateAction<
|
|
23
|
+
setCompleteChatHistory: import("react").Dispatch<import("react").SetStateAction<BaseMessage<import("@langchain/core/messages").MessageStructure, import("@langchain/core/messages").MessageType>[]>>;
|
|
24
|
+
customMessage: string;
|
|
25
|
+
graphState: any;
|
|
26
|
+
setGraphState: import("react").Dispatch<any>;
|
|
20
27
|
};
|