clippy-test 1.0.9 → 2.0.1

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.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +172 -0
  3. package/bin/oncall.js +396 -0
  4. package/dist/api.js +10 -1
  5. package/dist/cli.js +20 -20
  6. package/dist/config.js +7 -7
  7. package/dist/helpers/cli-helpers.d.ts +25 -0
  8. package/dist/helpers/cli-helpers.js +329 -0
  9. package/dist/helpers/config-helpers.js +189 -0
  10. package/dist/helpers/ripgrep-tool.d.ts +15 -0
  11. package/dist/helpers/ripgrep-tool.js +126 -0
  12. package/dist/index.js +225 -62
  13. package/dist/logsManager.d.ts +31 -0
  14. package/dist/logsManager.js +90 -0
  15. package/dist/postinstall.js +20 -0
  16. package/dist/tools/ripgrep.js +3 -3
  17. package/dist/useWebSocket.d.ts +14 -6
  18. package/dist/useWebSocket.js +290 -45
  19. package/dist/utils/version-check.d.ts +2 -0
  20. package/dist/utils/version-check.js +124 -0
  21. package/dist/utils.d.ts +16 -0
  22. package/dist/utils.js +125 -4
  23. package/dist/websocket-server.d.ts +24 -0
  24. package/dist/websocket-server.js +235 -0
  25. package/package.json +18 -5
  26. package/bin/clippy.js +0 -109
  27. package/dist/api.js.map +0 -1
  28. package/dist/cli.js.map +0 -1
  29. package/dist/code_hierarchy.js.map +0 -1
  30. package/dist/config.js.map +0 -1
  31. package/dist/index.js.map +0 -1
  32. package/dist/tools/code_hierarchy.d.ts +0 -8
  33. package/dist/tools/code_hierarchy.js +0 -78
  34. package/dist/tools/code_hierarchy.js.map +0 -1
  35. package/dist/tools/fetch_context.d.ts +0 -1
  36. package/dist/tools/fetch_context.js +0 -8
  37. package/dist/tools/fetch_context.js.map +0 -1
  38. package/dist/tools/ripgrep.js.map +0 -1
  39. package/dist/ui-graph.js.map +0 -1
  40. package/dist/useWebSocket.js.map +0 -1
  41. package/dist/utils.js.map +0 -1
@@ -0,0 +1,124 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import os from "os";
4
+ import { fileURLToPath } from "url";
5
+ import axios from "axios";
6
+ const ONCALL_DIR = path.join(os.homedir(), ".oncall");
7
+ const VERSION_CACHE_FILE = path.join(ONCALL_DIR, "version-cache.json");
8
+ const API_BASE_URL = "http://api.oncall.build/v2/api";
9
+ const CACHE_DURATION_MS = 24 * 60 * 60 * 1000;
10
+ function compareVersions(v1, v2) {
11
+ const parts1 = v1.split(".").map(Number);
12
+ const parts2 = v2.split(".").map(Number);
13
+ for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
14
+ const part1 = parts1[i] || 0;
15
+ const part2 = parts2[i] || 0;
16
+ if (part1 < part2)
17
+ return -1;
18
+ if (part1 > part2)
19
+ return 1;
20
+ }
21
+ return 0;
22
+ }
23
+ function isVersionDeprecated(currentVersion, minimumVersion) {
24
+ return compareVersions(currentVersion, minimumVersion) < 0;
25
+ }
26
+ function readVersionCache() {
27
+ if (fs.existsSync(VERSION_CACHE_FILE)) {
28
+ const content = fs.readFileSync(VERSION_CACHE_FILE, "utf8");
29
+ return JSON.parse(content);
30
+ }
31
+ return null;
32
+ }
33
+ function ensureOnCallDir() {
34
+ if (!fs.existsSync(ONCALL_DIR)) {
35
+ fs.mkdirSync(ONCALL_DIR, { recursive: true });
36
+ }
37
+ }
38
+ function writeVersionCache(cache) {
39
+ ensureOnCallDir();
40
+ fs.writeFileSync(VERSION_CACHE_FILE, JSON.stringify(cache, null, 2));
41
+ }
42
+ function shouldCheckVersion() {
43
+ const cache = readVersionCache();
44
+ if (!cache || !cache.lastCheck) {
45
+ return true;
46
+ }
47
+ const now = Date.now();
48
+ const timeSinceLastCheck = now - cache.lastCheck;
49
+ return timeSinceLastCheck >= CACHE_DURATION_MS;
50
+ }
51
+ async function fetchMinimumVersion() {
52
+ try {
53
+ const response = await axios.get(`${API_BASE_URL}/health/minimum-cli-version`);
54
+ if (response.data?.success && response.data?.minimumCliVersion) {
55
+ return response.data.minimumCliVersion;
56
+ }
57
+ }
58
+ catch (error) {
59
+ console.warn("Failed to check CLI version:", error instanceof Error ? error.message : "Unknown error");
60
+ }
61
+ return null;
62
+ }
63
+ function getCurrentVersion() {
64
+ try {
65
+ const __filename = fileURLToPath(import.meta.url);
66
+ const __dirname = path.dirname(__filename);
67
+ const possiblePaths = [
68
+ path.resolve(__dirname, "../package.json"),
69
+ path.resolve(__dirname, "../../package.json"),
70
+ ];
71
+ for (const pkgPath of possiblePaths) {
72
+ if (fs.existsSync(pkgPath)) {
73
+ const pkgJson = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
74
+ return pkgJson.version || "0.0.0";
75
+ }
76
+ }
77
+ return "0.0.0";
78
+ }
79
+ catch (error) {
80
+ return "0.0.0";
81
+ }
82
+ }
83
+ function formatDeprecationError(currentVersion, minimumVersion) {
84
+ return `
85
+ ⚠️ CLI VERSION DEPRECATED
86
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
87
+
88
+ Your current version: ${currentVersion}
89
+ Minimum required version: ${minimumVersion}
90
+
91
+ Please update to the latest version to continue using OnCall CLI.
92
+
93
+ To update, run:
94
+ npm install -g oncall-cli@latest
95
+
96
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
97
+ `;
98
+ }
99
+ export async function checkVersionCompatibility(forceCheck = false) {
100
+ const currentVersion = getCurrentVersion();
101
+ const cache = readVersionCache();
102
+ if (!forceCheck && cache?.lastCheck && !shouldCheckVersion()) {
103
+ return true;
104
+ }
105
+ const minimumVersion = await fetchMinimumVersion();
106
+ if (!minimumVersion) {
107
+ return true;
108
+ }
109
+ writeVersionCache({
110
+ lastCheck: Date.now(),
111
+ });
112
+ if (isVersionDeprecated(currentVersion, minimumVersion)) {
113
+ console.error(formatDeprecationError(currentVersion, minimumVersion));
114
+ return false;
115
+ }
116
+ return true;
117
+ }
118
+ export async function checkVersionAndExit() {
119
+ const isCompatible = await checkVersionCompatibility(true);
120
+ if (!isCompatible) {
121
+ process.exit(1);
122
+ }
123
+ }
124
+ //# sourceMappingURL=version-check.js.map
package/dist/utils.d.ts CHANGED
@@ -1 +1,17 @@
1
+ import { BaseMessage } from "langchain";
1
2
  export declare function getContextLines(fileName: string, lineNumber: number, before?: number, after?: number): string;
3
+ export declare function extractMessageContent(messages: BaseMessage[]): string;
4
+ /**
5
+ * Get a unique key for a message for deduplication purposes
6
+ * Uses message.id if available (string), otherwise checks other locations, then creates a fallback key
7
+ */
8
+ export declare function getMessageKey(message: BaseMessage): string;
9
+ /**
10
+ * Deduplicate messages array by message ID, keeping the last occurrence
11
+ * Preserves message order
12
+ */
13
+ export declare function deduplicateMessages(messages: BaseMessage[]): BaseMessage[];
14
+ export declare function groupMessageChunks(messages: BaseMessage[]): {
15
+ lastId: string;
16
+ messages: BaseMessage[][];
17
+ };
package/dist/utils.js CHANGED
@@ -1,10 +1,50 @@
1
1
  import * as fs from "fs";
2
+ import * as path from "path";
3
+ import { logd } from "./helpers/cli-helpers.js";
2
4
  //parameter to redis
3
5
  export function getContextLines(fileName, lineNumber, before = 30, after = 30) {
4
- const lines = fs.readFileSync(fileName, "utf-8").split("\n");
5
- const start = Math.max(0, lineNumber - before - 1);
6
- const end = Math.min(lines.length, lineNumber + after);
7
- return lines.slice(start, end).join("\n");
6
+ logd(`[getContextLines] 📥 Called with: fileName=${fileName}, lineNumber=${lineNumber}, before=${before}, after=${after}`);
7
+ try {
8
+ if (!fileName || typeof fileName !== "string") {
9
+ logd(`[getContextLines] ❌ ERROR: Invalid fileName: ${fileName}`);
10
+ return "";
11
+ }
12
+ if (typeof lineNumber !== "number" || lineNumber < 1) {
13
+ logd(`[getContextLines] ❌ ERROR: Invalid lineNumber: ${lineNumber}`);
14
+ return "";
15
+ }
16
+ const resolvedPath = path.resolve(fileName);
17
+ logd(`[getContextLines] 📁 Path resolution: original=${fileName}, resolved=${resolvedPath}, exists=${fs.existsSync(fileName)}`);
18
+ if (!fs.existsSync(fileName)) {
19
+ logd(`[getContextLines] ❌ ERROR: File not found: ${fileName}`);
20
+ logd(`[getContextLines] Attempted absolute path: ${resolvedPath}`);
21
+ return "";
22
+ }
23
+ const stats = fs.statSync(fileName);
24
+ logd(`[getContextLines] 📊 File stats: size=${stats.size}, isFile=${stats.isFile()}, isDirectory=${stats.isDirectory()}`);
25
+ const fileContent = fs.readFileSync(fileName, "utf-8");
26
+ logd(`[getContextLines] 📖 File read: contentLength=${fileContent.length}, hasContent=${fileContent.length > 0}`);
27
+ const lines = fileContent.split("\n");
28
+ const totalLines = lines.length;
29
+ logd(`[getContextLines] 📝 File split: totalLines=${totalLines}`);
30
+ const start = Math.max(0, lineNumber - before - 1);
31
+ const end = Math.min(totalLines, lineNumber + after);
32
+ logd(`[getContextLines] 🧮 Calculated indices: requestedLine=${lineNumber}, before=${before}, after=${after}, start=${start}, end=${end}, linesToExtract=${end - start}`);
33
+ if (lineNumber > totalLines) {
34
+ logd(`[getContextLines] ⚠️ WARNING: lineNumber (${lineNumber}) exceeds total lines (${totalLines})`);
35
+ }
36
+ if (lineNumber < 1) {
37
+ logd(`[getContextLines] ⚠️ WARNING: lineNumber (${lineNumber}) is less than 1`);
38
+ }
39
+ const extractedLines = lines.slice(start, end);
40
+ const result = extractedLines.join("\n");
41
+ logd(`[getContextLines] ✅ Extraction complete: extractedLineCount=${extractedLines.length}, resultLength=${result.length}, firstLine=${extractedLines[0]?.substring(0, 50) || "(empty)"}, lastLine=${extractedLines[extractedLines.length - 1]?.substring(0, 50) || "(empty)"}`);
42
+ return result;
43
+ }
44
+ catch (error) {
45
+ logd(`[getContextLines] ❌ EXCEPTION: error=${error instanceof Error ? error.message : String(error)}, fileName=${fileName}, lineNumber=${lineNumber}`);
46
+ return "";
47
+ }
8
48
  }
9
49
  //redis connection
10
50
  // const redisClient = createClient({
@@ -19,4 +59,85 @@ export function getContextLines(fileName, lineNumber, before = 30, after = 30) {
19
59
  // });
20
60
  // redisClient.connect();
21
61
  // export default redisClient;
62
+ export function extractMessageContent(messages) {
63
+ return messages.reduce((prev, message) => {
64
+ return prev + message.content;
65
+ }, "");
66
+ }
67
+ /**
68
+ * Get a unique key for a message for deduplication purposes
69
+ * Uses message.id if available (string), otherwise checks other locations, then creates a fallback key
70
+ */
71
+ export function getMessageKey(message) {
72
+ // Priority 1: Check message.id if it's a string (unique ID)
73
+ if (message.id && typeof message.id === "string") {
74
+ return message.id;
75
+ }
76
+ // Priority 2: Check response_metadata.id (some messages store ID here)
77
+ const msgAny = message;
78
+ if (msgAny.response_metadata?.id && typeof msgAny.response_metadata.id === "string") {
79
+ return msgAny.response_metadata.id;
80
+ }
81
+ // Priority 3: Check lc_kwargs.id (LangChain might preserve original kwargs)
82
+ if (msgAny.lc_kwargs?.id && typeof msgAny.lc_kwargs.id === "string") {
83
+ return msgAny.lc_kwargs.id;
84
+ }
85
+ // Priority 4: For ToolMessage, use tool_call_id as unique identifier
86
+ const toolCallId = msgAny.tool_call_id;
87
+ if (toolCallId && typeof toolCallId === "string") {
88
+ return `tool_${toolCallId}`;
89
+ }
90
+ // Fallback: create a key from content + type + tool_call_id (if available)
91
+ // This handles messages without IDs by creating a content-based key
92
+ // NOTE: This could cause false duplicates if two different messages have same content
93
+ const type = message.constructor.name || "Unknown";
94
+ let content = "";
95
+ if (typeof message.content === "string") {
96
+ content = message.content.substring(0, 50);
97
+ }
98
+ else if (message.content !== undefined && message.content !== null) {
99
+ const stringified = JSON.stringify(message.content);
100
+ content = stringified ? stringified.substring(0, 50) : "";
101
+ }
102
+ // Include a hash of full content to reduce collisions
103
+ const contentHash = typeof message.content === "string"
104
+ ? message.content.length.toString()
105
+ : "0";
106
+ return `${type}_${contentHash}_${content}_${toolCallId || ""}`;
107
+ }
108
+ /**
109
+ * Deduplicate messages array by message ID, keeping the last occurrence
110
+ * Preserves message order
111
+ */
112
+ export function deduplicateMessages(messages) {
113
+ const messageMap = new Map();
114
+ const order = [];
115
+ messages.forEach((msg) => {
116
+ const key = getMessageKey(msg);
117
+ if (!messageMap.has(key)) {
118
+ order.push(key);
119
+ }
120
+ // Keep the last occurrence of messages with the same ID
121
+ messageMap.set(key, msg);
122
+ });
123
+ // Return messages in original order, but deduplicated
124
+ return order.map((key) => messageMap.get(key)).filter(Boolean);
125
+ }
126
+ export function groupMessageChunks(messages) {
127
+ return messages.reduce((prev, message) => {
128
+ if (!prev)
129
+ prev = { lastId: "", messages: [] };
130
+ const messageKey = getMessageKey(message);
131
+ if (messageKey !== prev.lastId) {
132
+ prev.messages.push([message]);
133
+ prev.lastId = messageKey;
134
+ return prev;
135
+ }
136
+ else {
137
+ }
138
+ const lastMessageIndex = prev.messages.length - 1;
139
+ prev.messages[lastMessageIndex].push(message);
140
+ return prev;
141
+ }, { lastId: "", messages: [] });
142
+ }
22
143
  //# sourceMappingURL=utils.js.map
@@ -0,0 +1,24 @@
1
+ import { AddressInfo } from "net";
2
+ type Logger = Pick<Console, "log" | "info" | "warn" | "error">;
3
+ export interface OnCallWebSocketServerOptions {
4
+ port?: number;
5
+ host?: string;
6
+ logger?: Logger;
7
+ }
8
+ export declare class OnCallWebSocketServer {
9
+ private wss;
10
+ private readonly allProjects;
11
+ private readonly options;
12
+ constructor(options?: OnCallWebSocketServerOptions);
13
+ get address(): AddressInfo | null;
14
+ start(): Promise<void>;
15
+ stop(): Promise<void>;
16
+ private handleServerClose;
17
+ private handleConnection;
18
+ private handleMessage;
19
+ private send;
20
+ private normalizeProjectPayload;
21
+ private upsertProjectRegistration;
22
+ }
23
+ export declare function startOnCallWebSocketServer(options?: OnCallWebSocketServerOptions): Promise<OnCallWebSocketServer>;
24
+ export {};
@@ -0,0 +1,235 @@
1
+ import { once } from "events";
2
+ import { WebSocketServer, WebSocket } from "ws";
3
+ import { logd } from "./helpers/cli-helpers.js";
4
+ const DEFAULT_PORT = Number.parseInt(process.env.ONCALL_WS_PORT ?? "", 10) || 6111;
5
+ const DEFAULT_HOST = process.env.ONCALL_WS_HOST || "127.0.0.1";
6
+ export class OnCallWebSocketServer {
7
+ constructor(options = {}) {
8
+ this.wss = null;
9
+ this.allProjects = [];
10
+ this.options = {
11
+ port: options.port ?? DEFAULT_PORT,
12
+ host: options.host ?? DEFAULT_HOST,
13
+ logger: options.logger ?? console,
14
+ };
15
+ }
16
+ get address() {
17
+ if (!this.wss)
18
+ return null;
19
+ const addr = this.wss.address();
20
+ return typeof addr === "string" || addr === null ? null : addr;
21
+ }
22
+ async start() {
23
+ if (this.wss) {
24
+ // this.options.logger.warn("Attempted to start an already running server.");
25
+ return;
26
+ }
27
+ this.wss = new WebSocketServer({
28
+ host: this.options.host,
29
+ port: this.options.port,
30
+ });
31
+ this.wss.on("connection", (socket, request) => this.handleConnection(socket, request.headers));
32
+ this.wss.on("close", () => this.handleServerClose());
33
+ try {
34
+ await Promise.race([
35
+ once(this.wss, "listening"),
36
+ once(this.wss, "error").then(([error]) => {
37
+ throw error;
38
+ }),
39
+ ]);
40
+ }
41
+ catch (error) {
42
+ // this.options.logger.error(
43
+ // `Failed to start WebSocket server on ws://${this.options.host}:${this.options.port}`,
44
+ // error
45
+ // );
46
+ await this.stop();
47
+ if (error.code === "EADDRINUSE" ||
48
+ error.message.includes("address already in use")) {
49
+ throw `Failed to start the OnCall server.
50
+
51
+ Port 4466 is already in use.
52
+ Stop the other process or free the port and try again.
53
+ `;
54
+ }
55
+ else {
56
+ throw error;
57
+ }
58
+ }
59
+ }
60
+ async stop() {
61
+ if (!this.wss) {
62
+ return;
63
+ }
64
+ const server = this.wss;
65
+ this.wss = null;
66
+ await new Promise((resolve, reject) => {
67
+ server.close((err) => {
68
+ if (err) {
69
+ reject(err);
70
+ }
71
+ else {
72
+ resolve();
73
+ }
74
+ });
75
+ });
76
+ // this.options.logger.info("Server stopped.");
77
+ }
78
+ handleServerClose() {
79
+ // noop for now
80
+ }
81
+ handleConnection(socket, headers) {
82
+ // this.options.logger.info(
83
+ // `Client connected from ${headers["x-forwarded-for"] || "local"}`
84
+ // );
85
+ socket.on("message", (data) => this.handleMessage(socket, data));
86
+ socket.on("close", (code, reason) => {
87
+ // this.options.logger.info(
88
+ // `Client disconnected`
89
+ // );
90
+ });
91
+ socket.on("error", (error) => {
92
+ // this.options.logger.warn("Client error:", error);
93
+ socket.close(1011, "internal_error");
94
+ });
95
+ }
96
+ handleMessage(socket, raw) {
97
+ let payload;
98
+ try {
99
+ const serialized = typeof raw === "string" ? raw : raw.toString("utf8").trim();
100
+ if (!serialized)
101
+ return;
102
+ payload = JSON.parse(serialized);
103
+ }
104
+ catch (error) {
105
+ this.send(socket, {
106
+ type: "error",
107
+ message: "Invalid JSON payload",
108
+ });
109
+ // this.options.logger.warn("Invalid payload received:", error);
110
+ return;
111
+ }
112
+ switch (payload.type) {
113
+ case "register": {
114
+ const projectPayload = "project" in payload
115
+ ? payload.project
116
+ : undefined;
117
+ const project = this.normalizeProjectPayload(projectPayload);
118
+ if (!project) {
119
+ this.send(socket, {
120
+ type: "error",
121
+ message: "Invalid project payload for register channel",
122
+ });
123
+ return;
124
+ }
125
+ const projectRecord = this.upsertProjectRegistration(project);
126
+ this.send(socket, {
127
+ type: "register_ack",
128
+ projectId: project.id,
129
+ totalRegisteredProjects: projectRecord.projects.length,
130
+ });
131
+ break;
132
+ }
133
+ case "fetch_projects": {
134
+ logd("Received the fetch_projects_req");
135
+ let projectRecord = this.allProjects.find((entry) => entry.id === payload.id);
136
+ logd("Found the following: " + JSON.stringify(projectRecord.projects));
137
+ this.send(socket, {
138
+ type: "fetch_projects_ack",
139
+ projects: projectRecord.projects,
140
+ });
141
+ logd("Sent the response for fetch_projects");
142
+ break;
143
+ }
144
+ default: {
145
+ this.send(socket, {
146
+ type: "ack",
147
+ message: `Unhandled message type "${payload.type}"`,
148
+ });
149
+ }
150
+ }
151
+ }
152
+ send(socket, message) {
153
+ if (socket.readyState !== WebSocket.OPEN) {
154
+ return;
155
+ }
156
+ try {
157
+ socket.send(JSON.stringify(message));
158
+ }
159
+ catch (error) {
160
+ // this.options.logger.warn("Failed to send message to client:", error);
161
+ }
162
+ }
163
+ normalizeProjectPayload(payload) {
164
+ if (!payload ||
165
+ typeof payload.id !== "string" ||
166
+ typeof payload.description !== "string" ||
167
+ typeof payload.path !== "string") {
168
+ return null;
169
+ }
170
+ const id = payload.id.trim();
171
+ const description = payload.description.trim();
172
+ const projectPath = payload.path.trim();
173
+ const name = typeof payload.name === "string" && payload.name.trim()
174
+ ? payload.name.trim()
175
+ : undefined;
176
+ const window_id = typeof payload.window_id === "number" ? payload.window_id : Date.now();
177
+ const logs_available = typeof payload.logs_available === "boolean"
178
+ ? payload.logs_available
179
+ : true;
180
+ const code_available = typeof payload.code_available === "boolean"
181
+ ? payload.code_available
182
+ : true;
183
+ if (!id || !description || !projectPath) {
184
+ return null;
185
+ }
186
+ return {
187
+ id,
188
+ description,
189
+ path: projectPath,
190
+ name,
191
+ window_id,
192
+ logs_available,
193
+ code_available,
194
+ };
195
+ }
196
+ upsertProjectRegistration(project) {
197
+ let projectRecord = this.allProjects.find((entry) => entry.id === project.id);
198
+ if (!projectRecord) {
199
+ projectRecord = { id: project.id, projects: [] };
200
+ this.allProjects.push(projectRecord);
201
+ }
202
+ const existingProject = projectRecord.projects.find((item) => item.path === project.path);
203
+ if (existingProject) {
204
+ existingProject.description = project.description;
205
+ if (project.name) {
206
+ existingProject.name = project.name;
207
+ }
208
+ existingProject.window_id = project.window_id;
209
+ existingProject.logs_available = project.logs_available;
210
+ existingProject.code_available = project.code_available;
211
+ }
212
+ else {
213
+ projectRecord.projects.push({
214
+ path: project.path,
215
+ description: project.description,
216
+ name: project.name,
217
+ window_id: project.window_id,
218
+ logs_available: project.logs_available,
219
+ code_available: project.code_available,
220
+ });
221
+ }
222
+ // this.options.logger.info(
223
+ // `Registered project "${project.id}" -> ${project.path} (total directories: ${projectRecord.projects.length})`
224
+ // );
225
+ // const snapshot = JSON.stringify(this.allProjects, null, 2);
226
+ // this.options.logger.info(`Current projects: ${snapshot}`);
227
+ return projectRecord;
228
+ }
229
+ }
230
+ export async function startOnCallWebSocketServer(options) {
231
+ const server = new OnCallWebSocketServer(options);
232
+ await server.start();
233
+ return server;
234
+ }
235
+ //# sourceMappingURL=websocket-server.js.map
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "clippy-test",
3
- "version": "1.0.9",
3
+ "version": "2.0.1",
4
4
  "type": "module",
5
5
  "bin": {
6
- "clippy": "bin/clippy.js"
6
+ "oncall": "bin/oncall.js"
7
7
  },
8
8
  "files": [
9
9
  "bin/",
@@ -15,24 +15,37 @@
15
15
  "start": "tsx index.tsx",
16
16
  "dev": "tsx index.tsx",
17
17
  "code-hierarchy": "tsx code_hierarchy.ts",
18
- "build": "tsc",
18
+ "postinstall": "node dist/postinstall.js",
19
+ "build": "patch-package && tsc && npm run copy-js && npm run clean-maps",
20
+ "copy-js": "mkdir -p dist/helpers && cp helpers/config-helpers.js dist/helpers/config-helpers.js && cp postinstall.js dist/postinstall.js",
21
+ "clean-maps": "find dist -name '*.map' -type f -delete 2>/dev/null || true",
19
22
  "prepublishOnly": "npm run build"
20
23
  },
21
24
  "dependencies": {
25
+ "@langchain/anthropic": "^1.3.3",
26
+ "@langchain/core": "^1.1.0",
27
+ "@langchain/openai": "^1.2.0",
28
+ "@types/ws": "^8.18.1",
22
29
  "axios": "^1.12.2",
23
30
  "dotenv": "^17.2.3",
24
31
  "ignore": "^5.3.2",
25
32
  "ink": "^6.3.1",
26
33
  "ink-spinner": "^5.0.0",
27
34
  "ink-text-input": "^6.0.0",
35
+ "js-yaml": "^4.1.1",
36
+ "langchain": "^1.1.1",
28
37
  "marked": "^15.0.0",
29
38
  "marked-terminal": "^7.3.0",
30
- "node-pty": "^1.0.0",
31
- "react": "^19.2.0"
39
+ "node-pty": "0.10.1",
40
+ "react": "^19.2.0",
41
+ "ripgrep-node": "^1.0.0",
42
+ "ws": "^8.18.3",
43
+ "yaml": "^2.8.2"
32
44
  },
33
45
  "devDependencies": {
34
46
  "@types/node": "^24.9.1",
35
47
  "@types/react": "^19.1.13",
48
+ "patch-package": "^8.0.1",
36
49
  "tsx": "^4.19.2",
37
50
  "typescript": "^5.9.3"
38
51
  }