@tyvm/knowhow 0.0.69 → 0.0.71
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/docs/shell-commands.md +174 -0
- package/package.json +1 -1
- package/src/agents/base/base.ts +4 -5
- package/src/agents/developer/developer.ts +21 -13
- package/src/agents/tools/agentCall.ts +4 -2
- package/src/agents/tools/fileSearch.ts +5 -1
- package/src/agents/tools/startAgentTask.ts +131 -22
- package/src/agents/tools/stringReplace.ts +42 -12
- package/src/chat/CliChatService.ts +57 -11
- package/src/chat/modules/AgentModule.ts +72 -12
- package/src/chat/modules/CustomCommandsModule.ts +79 -0
- package/src/chat/modules/InternalChatModule.ts +11 -1
- package/src/chat/modules/ShellCommandModule.ts +96 -0
- package/src/chat/modules/index.ts +1 -0
- package/src/chat/types.ts +14 -2
- package/src/chat.ts +16 -13
- package/src/cli.ts +16 -6
- package/src/clients/anthropic.ts +82 -112
- package/src/clients/gemini.ts +445 -87
- package/src/clients/index.ts +125 -0
- package/src/clients/knowhow.ts +81 -0
- package/src/clients/openai.ts +256 -145
- package/src/clients/pricing/anthropic.ts +90 -0
- package/src/clients/pricing/google.ts +65 -0
- package/src/clients/pricing/index.ts +4 -0
- package/src/clients/pricing/openai.ts +134 -0
- package/src/clients/pricing/xai.ts +62 -0
- package/src/clients/types.ts +170 -1
- package/src/clients/xai.ts +275 -46
- package/src/config.ts +61 -15
- package/src/embeddings.ts +9 -1
- package/src/microphone.ts +15 -16
- package/src/migrations.ts +151 -0
- package/src/plugins/AgentsMdPlugin.ts +118 -0
- package/src/plugins/PluginBase.ts +8 -0
- package/src/plugins/downloader/downloader.ts +5 -6
- package/src/plugins/embedding.ts +10 -8
- package/src/plugins/exec.ts +70 -0
- package/src/plugins/github.ts +120 -74
- package/src/plugins/language.ts +11 -13
- package/src/plugins/plugins.ts +25 -4
- package/src/plugins/tmux.ts +132 -0
- package/src/plugins/types.ts +1 -0
- package/src/plugins/vim.ts +14 -1
- package/src/services/AgentSyncFs.ts +417 -0
- package/src/services/{AgentSynchronization.ts → AgentSyncKnowhowWeb.ts} +2 -2
- package/src/services/EventService.ts +0 -1
- package/src/services/KnowhowClient.ts +106 -0
- package/src/services/index.ts +4 -2
- package/src/types.ts +57 -4
- package/src/worker.ts +11 -6
- package/tests/manual/modalities/README.md +157 -0
- package/tests/manual/modalities/google.modalities.test.ts +335 -0
- package/tests/manual/modalities/openai.modalities.test.ts +329 -0
- package/tests/manual/modalities/streaming.test.ts +260 -0
- package/tests/manual/modalities/xai.modalities.test.ts +307 -0
- package/tests/plugins/language/languagePlugin-content-triggers.test.ts +5 -5
- package/tests/plugins/language/languagePlugin-integration.test.ts +1 -1
- package/tests/plugins/language/languagePlugin.test.ts +17 -8
- package/ts_build/package.json +1 -1
- package/ts_build/src/agents/base/base.d.ts +3 -3
- package/ts_build/src/agents/base/base.js +1 -1
- package/ts_build/src/agents/base/base.js.map +1 -1
- package/ts_build/src/agents/developer/developer.js +21 -12
- package/ts_build/src/agents/developer/developer.js.map +1 -1
- package/ts_build/src/agents/tools/agentCall.js +4 -2
- package/ts_build/src/agents/tools/agentCall.js.map +1 -1
- package/ts_build/src/agents/tools/executeScript/index.d.ts +1 -1
- package/ts_build/src/agents/tools/fileSearch.js +2 -1
- package/ts_build/src/agents/tools/fileSearch.js.map +1 -1
- package/ts_build/src/agents/tools/github/index.d.ts +1 -1
- package/ts_build/src/agents/tools/startAgentTask.d.ts +2 -1
- package/ts_build/src/agents/tools/startAgentTask.js +118 -17
- package/ts_build/src/agents/tools/startAgentTask.js.map +1 -1
- package/ts_build/src/agents/tools/stringReplace.js +29 -12
- package/ts_build/src/agents/tools/stringReplace.js.map +1 -1
- package/ts_build/src/chat/CliChatService.d.ts +4 -0
- package/ts_build/src/chat/CliChatService.js +39 -5
- package/ts_build/src/chat/CliChatService.js.map +1 -1
- package/ts_build/src/chat/modules/AgentModule.d.ts +4 -1
- package/ts_build/src/chat/modules/AgentModule.js +49 -11
- package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
- package/ts_build/src/chat/modules/CustomCommandsModule.d.ts +9 -0
- package/ts_build/src/chat/modules/CustomCommandsModule.js +58 -0
- package/ts_build/src/chat/modules/CustomCommandsModule.js.map +1 -0
- package/ts_build/src/chat/modules/InternalChatModule.d.ts +2 -0
- package/ts_build/src/chat/modules/InternalChatModule.js +10 -0
- package/ts_build/src/chat/modules/InternalChatModule.js.map +1 -1
- package/ts_build/src/chat/modules/ShellCommandModule.d.ts +8 -0
- package/ts_build/src/chat/modules/ShellCommandModule.js +83 -0
- package/ts_build/src/chat/modules/ShellCommandModule.js.map +1 -0
- package/ts_build/src/chat/modules/index.d.ts +1 -0
- package/ts_build/src/chat/modules/index.js +3 -1
- package/ts_build/src/chat/modules/index.js.map +1 -1
- package/ts_build/src/chat/types.d.ts +11 -1
- package/ts_build/src/chat.js +16 -13
- package/ts_build/src/chat.js.map +1 -1
- package/ts_build/src/cli.js +10 -3
- package/ts_build/src/cli.js.map +1 -1
- package/ts_build/src/clients/anthropic.d.ts +5 -1
- package/ts_build/src/clients/anthropic.js +61 -112
- package/ts_build/src/clients/anthropic.js.map +1 -1
- package/ts_build/src/clients/gemini.d.ts +80 -2
- package/ts_build/src/clients/gemini.js +336 -74
- package/ts_build/src/clients/gemini.js.map +1 -1
- package/ts_build/src/clients/index.d.ts +9 -1
- package/ts_build/src/clients/index.js +65 -0
- package/ts_build/src/clients/index.js.map +1 -1
- package/ts_build/src/clients/knowhow.d.ts +9 -1
- package/ts_build/src/clients/knowhow.js +43 -0
- package/ts_build/src/clients/knowhow.js.map +1 -1
- package/ts_build/src/clients/openai.d.ts +9 -1
- package/ts_build/src/clients/openai.js +201 -133
- package/ts_build/src/clients/openai.js.map +1 -1
- package/ts_build/src/clients/pricing/anthropic.d.ts +17 -0
- package/ts_build/src/clients/pricing/anthropic.js +93 -0
- package/ts_build/src/clients/pricing/anthropic.js.map +1 -0
- package/ts_build/src/clients/pricing/google.d.ts +73 -0
- package/ts_build/src/clients/pricing/google.js +68 -0
- package/ts_build/src/clients/pricing/google.js.map +1 -0
- package/ts_build/src/clients/pricing/index.d.ts +4 -0
- package/ts_build/src/clients/pricing/index.js +14 -0
- package/ts_build/src/clients/pricing/index.js.map +1 -0
- package/ts_build/src/clients/pricing/openai.d.ts +7 -0
- package/ts_build/src/clients/pricing/openai.js +137 -0
- package/ts_build/src/clients/pricing/openai.js.map +1 -0
- package/ts_build/src/clients/pricing/xai.d.ts +26 -0
- package/ts_build/src/clients/pricing/xai.js +59 -0
- package/ts_build/src/clients/pricing/xai.js.map +1 -0
- package/ts_build/src/clients/types.d.ts +135 -0
- package/ts_build/src/clients/xai.d.ts +9 -1
- package/ts_build/src/clients/xai.js +178 -46
- package/ts_build/src/clients/xai.js.map +1 -1
- package/ts_build/src/config.d.ts +1 -0
- package/ts_build/src/config.js +45 -16
- package/ts_build/src/config.js.map +1 -1
- package/ts_build/src/embeddings.js +8 -1
- package/ts_build/src/embeddings.js.map +1 -1
- package/ts_build/src/microphone.js +7 -9
- package/ts_build/src/microphone.js.map +1 -1
- package/ts_build/src/migrations.d.ts +17 -0
- package/ts_build/src/migrations.js +86 -0
- package/ts_build/src/migrations.js.map +1 -0
- package/ts_build/src/plugins/AgentsMdPlugin.d.ts +13 -0
- package/ts_build/src/plugins/AgentsMdPlugin.js +118 -0
- package/ts_build/src/plugins/AgentsMdPlugin.js.map +1 -0
- package/ts_build/src/plugins/PluginBase.d.ts +1 -0
- package/ts_build/src/plugins/PluginBase.js +3 -0
- package/ts_build/src/plugins/PluginBase.js.map +1 -1
- package/ts_build/src/plugins/downloader/downloader.js +5 -5
- package/ts_build/src/plugins/downloader/downloader.js.map +1 -1
- package/ts_build/src/plugins/embedding.js +9 -8
- package/ts_build/src/plugins/embedding.js.map +1 -1
- package/ts_build/src/plugins/exec.d.ts +10 -0
- package/ts_build/src/plugins/exec.js +56 -0
- package/ts_build/src/plugins/exec.js.map +1 -0
- package/ts_build/src/plugins/github.js +93 -51
- package/ts_build/src/plugins/github.js.map +1 -1
- package/ts_build/src/plugins/language.js +14 -11
- package/ts_build/src/plugins/language.js.map +1 -1
- package/ts_build/src/plugins/plugins.d.ts +1 -0
- package/ts_build/src/plugins/plugins.js +19 -1
- package/ts_build/src/plugins/plugins.js.map +1 -1
- package/ts_build/src/plugins/tmux.d.ts +14 -0
- package/ts_build/src/plugins/tmux.js +108 -0
- package/ts_build/src/plugins/tmux.js.map +1 -0
- package/ts_build/src/plugins/types.d.ts +1 -0
- package/ts_build/src/plugins/vim.js +11 -1
- package/ts_build/src/plugins/vim.js.map +1 -1
- package/ts_build/src/services/AgentSyncFs.d.ts +34 -0
- package/ts_build/src/services/AgentSyncFs.js +325 -0
- package/ts_build/src/services/AgentSyncFs.js.map +1 -0
- package/ts_build/src/services/AgentSyncKnowhowWeb.d.ts +29 -0
- package/ts_build/src/services/AgentSyncKnowhowWeb.js +178 -0
- package/ts_build/src/services/AgentSyncKnowhowWeb.js.map +1 -0
- package/ts_build/src/services/AgentSynchronization.d.ts +1 -1
- package/ts_build/src/services/AgentSynchronization.js +3 -3
- package/ts_build/src/services/AgentSynchronization.js.map +1 -1
- package/ts_build/src/services/EventService.js.map +1 -1
- package/ts_build/src/services/KnowhowClient.d.ts +9 -1
- package/ts_build/src/services/KnowhowClient.js +58 -0
- package/ts_build/src/services/KnowhowClient.js.map +1 -1
- package/ts_build/src/services/index.d.ts +2 -1
- package/ts_build/src/services/index.js +2 -1
- package/ts_build/src/services/index.js.map +1 -1
- package/ts_build/src/types.d.ts +26 -1
- package/ts_build/src/types.js +45 -4
- package/ts_build/src/types.js.map +1 -1
- package/ts_build/src/utils/PersistentInputManager.d.ts +28 -0
- package/ts_build/src/utils/PersistentInputManager.js +293 -0
- package/ts_build/src/utils/PersistentInputManager.js.map +1 -0
- package/ts_build/src/worker.js +2 -2
- package/ts_build/src/worker.js.map +1 -1
- package/ts_build/tests/manual/modalities/google.modalities.test.d.ts +1 -0
- package/ts_build/tests/manual/modalities/google.modalities.test.js +252 -0
- package/ts_build/tests/manual/modalities/google.modalities.test.js.map +1 -0
- package/ts_build/tests/manual/modalities/openai.modalities.test.d.ts +1 -0
- package/ts_build/tests/manual/modalities/openai.modalities.test.js +252 -0
- package/ts_build/tests/manual/modalities/openai.modalities.test.js.map +1 -0
- package/ts_build/tests/manual/modalities/streaming.test.d.ts +1 -0
- package/ts_build/tests/manual/modalities/streaming.test.js +206 -0
- package/ts_build/tests/manual/modalities/streaming.test.js.map +1 -0
- package/ts_build/tests/manual/modalities/xai.modalities.test.d.ts +1 -0
- package/ts_build/tests/manual/modalities/xai.modalities.test.js +226 -0
- package/ts_build/tests/manual/modalities/xai.modalities.test.js.map +1 -0
- package/ts_build/tests/manual/persistent-input-test.d.ts +1 -0
- package/ts_build/tests/manual/persistent-input-test.js +35 -0
- package/ts_build/tests/manual/persistent-input-test.js.map +1 -0
- package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js +5 -5
- package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js.map +1 -1
- package/ts_build/tests/plugins/language/languagePlugin-integration.test.js +1 -1
- package/ts_build/tests/plugins/language/languagePlugin-integration.test.js.map +1 -1
- package/ts_build/tests/plugins/language/languagePlugin.test.js +17 -7
- package/ts_build/tests/plugins/language/languagePlugin.test.js.map +1 -1
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { PluginBase, PluginMeta } from "./PluginBase";
|
|
4
|
+
import { Plugin, PluginContext } from "./types";
|
|
5
|
+
import { MinimalEmbedding } from "../types";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* AgentsMdPlugin - Traverses directory tree upward from edited files to find
|
|
9
|
+
* agents.md files and alerts the agent about their presence.
|
|
10
|
+
*/
|
|
11
|
+
export class AgentsMdPlugin extends PluginBase implements Plugin {
|
|
12
|
+
static readonly meta: PluginMeta = {
|
|
13
|
+
key: "agents-md",
|
|
14
|
+
name: "AgentsMd Plugin",
|
|
15
|
+
description:
|
|
16
|
+
"Alerts the agent when an agents.md file is found near an edited file",
|
|
17
|
+
requires: [],
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
meta = AgentsMdPlugin.meta;
|
|
21
|
+
|
|
22
|
+
constructor(context: PluginContext) {
|
|
23
|
+
super(context);
|
|
24
|
+
this.setupEventHandlers();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private setupEventHandlers() {
|
|
28
|
+
const events = this.context?.Events;
|
|
29
|
+
if (!events) return;
|
|
30
|
+
|
|
31
|
+
const fileEvents = [
|
|
32
|
+
"file:pre-write",
|
|
33
|
+
"file:post-write",
|
|
34
|
+
"file:write",
|
|
35
|
+
"file:edit",
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
fileEvents.forEach((eventType) => {
|
|
39
|
+
events.on(eventType, async (eventData: any) => {
|
|
40
|
+
await this.handleFileEvent(eventData);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private findAgentsMd(startPath: string): string | null {
|
|
46
|
+
// Resolve to absolute path
|
|
47
|
+
const absoluteStart = path.isAbsolute(startPath)
|
|
48
|
+
? startPath
|
|
49
|
+
: path.resolve(startPath);
|
|
50
|
+
|
|
51
|
+
// Start from the directory of the file
|
|
52
|
+
let currentDir = fs.existsSync(absoluteStart)
|
|
53
|
+
? fs.statSync(absoluteStart).isDirectory()
|
|
54
|
+
? absoluteStart
|
|
55
|
+
: path.dirname(absoluteStart)
|
|
56
|
+
: path.dirname(absoluteStart);
|
|
57
|
+
|
|
58
|
+
const root = path.parse(currentDir).root;
|
|
59
|
+
|
|
60
|
+
while (true) {
|
|
61
|
+
const agentsMdPath = path.join(currentDir, "agents.md");
|
|
62
|
+
if (fs.existsSync(agentsMdPath)) {
|
|
63
|
+
return agentsMdPath;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Stop at filesystem root
|
|
67
|
+
if (currentDir === root) {
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const parentDir = path.dirname(currentDir);
|
|
72
|
+
// If we can't go up anymore, stop
|
|
73
|
+
if (parentDir === currentDir) {
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
currentDir = parentDir;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private async handleFileEvent(eventData: any) {
|
|
83
|
+
try {
|
|
84
|
+
const filePath = eventData?.filePath || eventData?.path || eventData;
|
|
85
|
+
if (!filePath || typeof filePath !== "string") {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const agentsMdPath = this.findAgentsMd(filePath);
|
|
90
|
+
if (!agentsMdPath) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const events = this.context?.Events;
|
|
95
|
+
if (!events) return;
|
|
96
|
+
|
|
97
|
+
const alertMessage = `There is an agents.md file detected near the edited file at \`${agentsMdPath}\`. You should read it if you haven't already.`;
|
|
98
|
+
|
|
99
|
+
events.emit("agent:msg", alertMessage);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error("AGENTS-MD PLUGIN: Error handling file event:", error);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async call(input?: string): Promise<string> {
|
|
106
|
+
if (input) {
|
|
107
|
+
const agentsMdPath = this.findAgentsMd(input);
|
|
108
|
+
if (agentsMdPath) {
|
|
109
|
+
return `There is an agents.md file detected near \`${input}\` at \`${agentsMdPath}\`. You should read it if you haven't already.`;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return "";
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async embed(input: string): Promise<MinimalEmbedding[]> {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -43,6 +43,14 @@ export abstract class PluginBase implements Plugin {
|
|
|
43
43
|
return true; // subclasses override if needed
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/* ------------------------------------------------------------------ */
|
|
47
|
+
/** Default callMany implementation - delegates to call ------------ */
|
|
48
|
+
/* ------------------------------------------------------------------ */
|
|
49
|
+
async callMany(input?: string): Promise<string> {
|
|
50
|
+
// Default behavior: callMany just calls call
|
|
51
|
+
return this.call(input);
|
|
52
|
+
}
|
|
53
|
+
|
|
46
54
|
/* ------------------------------------------------------------------ */
|
|
47
55
|
/** Mandatory plugin actions ---------------------------------------- */
|
|
48
56
|
/* ------------------------------------------------------------------ */
|
|
@@ -5,10 +5,8 @@ import Logger from "progress-estimator";
|
|
|
5
5
|
import { DownloadInfo, KeyframeInfo, TranscriptChunk } from "./types";
|
|
6
6
|
import { visionTool } from "../../agents/tools/visionTool";
|
|
7
7
|
import { execAsync, fileExists, readFile, mkdir } from "../../utils";
|
|
8
|
-
import OpenAI from "openai";
|
|
9
8
|
import { Clients } from "../../clients";
|
|
10
9
|
import { Models } from "../../types";
|
|
11
|
-
import { openai } from "../../ai";
|
|
12
10
|
|
|
13
11
|
const logger = Logger();
|
|
14
12
|
|
|
@@ -132,7 +130,6 @@ export class DownloaderService {
|
|
|
132
130
|
}
|
|
133
131
|
|
|
134
132
|
const allTranscripts = [];
|
|
135
|
-
const openAi = openai();
|
|
136
133
|
for (const file of files) {
|
|
137
134
|
const chunkName = path.parse(file).name;
|
|
138
135
|
const chunkTranscriptPath = path.join(
|
|
@@ -159,9 +156,11 @@ export class DownloaderService {
|
|
|
159
156
|
}
|
|
160
157
|
|
|
161
158
|
console.log("Transcribing", file);
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
159
|
+
const fileBuffer = fs.readFileSync(file);
|
|
160
|
+
const transcript = await this.clients
|
|
161
|
+
.createAudioTranscription("openai", {
|
|
162
|
+
file: fileBuffer,
|
|
163
|
+
fileName: path.basename(file),
|
|
165
164
|
model: "whisper-1",
|
|
166
165
|
})
|
|
167
166
|
.catch((e) => {
|
package/src/plugins/embedding.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "../embeddings";
|
|
8
8
|
|
|
9
9
|
import { PluginBase, PluginMeta } from "./PluginBase";
|
|
10
|
-
import {
|
|
10
|
+
import { spawn } from "child_process";
|
|
11
11
|
|
|
12
12
|
export class EmbeddingPlugin extends PluginBase {
|
|
13
13
|
static readonly meta: PluginMeta = {
|
|
@@ -30,17 +30,19 @@ export class EmbeddingPlugin extends PluginBase {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
* Handle file:post-edit events by triggering embedding
|
|
33
|
+
* Handle file:post-edit events by triggering embedding in a separate process
|
|
34
34
|
* @param payload The event payload containing filePath
|
|
35
35
|
* @returns Status message about embedding operation
|
|
36
36
|
*/
|
|
37
37
|
async handleFilePostEdit(payload: { filePath: string }): Promise<string> {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
const child = spawn("knowhow", ["embed"], {
|
|
39
|
+
detached: true,
|
|
40
|
+
stdio: "ignore",
|
|
41
|
+
cwd: process.cwd(),
|
|
42
|
+
});
|
|
43
|
+
child.unref();
|
|
44
|
+
console.log(`EMBEDDING PLUGIN: Started 'knowhow embed' in background (pid: ${child.pid})`);
|
|
45
|
+
return "Embedding started in background process";
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
async call(userPrompt: string): Promise<string> {
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { PluginBase, PluginMeta } from "./PluginBase";
|
|
2
|
+
import { PluginContext } from "./types";
|
|
3
|
+
import { execSync } from "child_process";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Exec Plugin - Execute shell commands from language config
|
|
7
|
+
* This allows language config entries to trigger shell commands
|
|
8
|
+
*/
|
|
9
|
+
export class ExecPlugin extends PluginBase {
|
|
10
|
+
static readonly meta: PluginMeta = {
|
|
11
|
+
key: "exec",
|
|
12
|
+
name: "Exec Plugin",
|
|
13
|
+
requires: [],
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
meta = ExecPlugin.meta;
|
|
17
|
+
|
|
18
|
+
constructor(context: PluginContext) {
|
|
19
|
+
super(context);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async callMany(input?: string): Promise<string> {
|
|
23
|
+
// Only execute during callMany if input starts with ! or /!
|
|
24
|
+
if (!input) {
|
|
25
|
+
return "";
|
|
26
|
+
}
|
|
27
|
+
const trimmed = input.trim();
|
|
28
|
+
if (trimmed.startsWith("!") || trimmed.startsWith("/!")) {
|
|
29
|
+
return this.call(input);
|
|
30
|
+
}
|
|
31
|
+
return "";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async call(input: string): Promise<string> {
|
|
35
|
+
// Input should be the command to execute
|
|
36
|
+
const command = input.trim();
|
|
37
|
+
|
|
38
|
+
if (!command) {
|
|
39
|
+
return "EXEC PLUGIN: No command provided";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
console.log(`EXEC PLUGIN: Executing: ${command}`);
|
|
44
|
+
|
|
45
|
+
// Execute the command
|
|
46
|
+
const result = execSync(command, {
|
|
47
|
+
encoding: "utf8",
|
|
48
|
+
cwd: process.cwd(),
|
|
49
|
+
maxBuffer: 10 * 1024 * 1024, // 10MB buffer
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return `EXEC PLUGIN: Command output from \`${command}\`:\n\`\`\`\n${result}\n\`\`\``;
|
|
53
|
+
} catch (error: any) {
|
|
54
|
+
const errorMessage = error.message;
|
|
55
|
+
const stderr = error.stderr || "";
|
|
56
|
+
const stdout = error.stdout || "";
|
|
57
|
+
|
|
58
|
+
console.error(`EXEC PLUGIN: Command failed: ${errorMessage}`);
|
|
59
|
+
if (stderr) {
|
|
60
|
+
console.error(stderr);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return `EXEC PLUGIN: Command \`${command}\` failed:\n\`\`\`\n${stdout}\n${stderr}\n${errorMessage}\n\`\`\``;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async embed(input: string) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
}
|
package/src/plugins/github.ts
CHANGED
|
@@ -74,29 +74,45 @@ export class GitHubPlugin extends PluginBase {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
async getDiff(url: string) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
77
|
+
try {
|
|
78
|
+
const { owner, repo, pullNumber } = this.parseUrl(url);
|
|
79
|
+
console.log(
|
|
80
|
+
`GITHUB PLUGIN: Loading diff for ${owner}/${repo}#${pullNumber}`
|
|
81
|
+
);
|
|
82
|
+
const { data: diff } = await this.octokit.rest.pulls.get({
|
|
83
|
+
owner,
|
|
84
|
+
repo,
|
|
85
|
+
pull_number: parseInt(pullNumber, 10),
|
|
86
|
+
mediaType: {
|
|
87
|
+
format: "diff",
|
|
88
|
+
},
|
|
89
|
+
});
|
|
89
90
|
|
|
90
|
-
|
|
91
|
+
return diff;
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.error(`GITHUB PLUGIN: Failed to get diff for ${url}:`, error.message);
|
|
94
|
+
if (error.status === 401) {
|
|
95
|
+
console.error("GITHUB PLUGIN: Authentication failed. Please check your GITHUB_TOKEN.");
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
91
99
|
}
|
|
92
100
|
|
|
93
|
-
getPR(url: string) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
101
|
+
async getPR(url: string) {
|
|
102
|
+
try {
|
|
103
|
+
const { owner, repo, pullNumber } = this.parseUrl(url);
|
|
104
|
+
return await this.octokit.rest.pulls.get({
|
|
105
|
+
owner,
|
|
106
|
+
repo,
|
|
107
|
+
pull_number: parseInt(pullNumber, 10),
|
|
108
|
+
});
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.error(`GITHUB PLUGIN: Failed to get PR for ${url}:`, error.message);
|
|
111
|
+
if (error.status === 401) {
|
|
112
|
+
console.error("GITHUB PLUGIN: Authentication failed. Please check your GITHUB_TOKEN.");
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
100
116
|
}
|
|
101
117
|
|
|
102
118
|
getLengthOfHunks(hunks: ReturnType<typeof parseHunks>) {
|
|
@@ -110,37 +126,49 @@ export class GitHubPlugin extends PluginBase {
|
|
|
110
126
|
async getParsedDiffs(urls: string[]) {
|
|
111
127
|
return Promise.all(
|
|
112
128
|
urls.map(async (url) => {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
129
|
+
try {
|
|
130
|
+
const diff = await this.getDiff(url);
|
|
131
|
+
|
|
132
|
+
// If getDiff returned null (auth error), skip this URL
|
|
133
|
+
if (!diff) {
|
|
134
|
+
console.log(`GITHUB PLUGIN: Skipping ${url} due to error`);
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
let parsed = parseHunks(diff.toString());
|
|
139
|
+
|
|
140
|
+
console.log(`GITHUB PLUGIN: Parsed ${parsed.length} hunks`);
|
|
141
|
+
|
|
142
|
+
const averageHunkSize =
|
|
143
|
+
parsed.reduce((acc, hunk) => acc + hunk.lines.length, 0) /
|
|
144
|
+
parsed.length;
|
|
145
|
+
|
|
146
|
+
const totalCharacters = parsed
|
|
147
|
+
.flatMap((hunk) => [...hunk.additions, ...hunk.subtractions])
|
|
148
|
+
.reduce((acc, line) => acc + line.length, 0);
|
|
149
|
+
|
|
150
|
+
console.log(
|
|
151
|
+
`GITHUB PLUGIN: Average hunk size: ${averageHunkSize}, total characters: ${totalCharacters}`
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
const MAX_CHARACTERS = 10000;
|
|
155
|
+
const average = MAX_CHARACTERS / averageHunkSize;
|
|
156
|
+
const PER_HUNK_LIMIT = Math.max(average, 2000);
|
|
157
|
+
|
|
158
|
+
parsed = parsed.filter((hunk) => {
|
|
159
|
+
return this.getLengthOfHunks([hunk]) <= PER_HUNK_LIMIT;
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
console.log(
|
|
163
|
+
`GITHUB PLUGIN: Filtered to ${
|
|
164
|
+
parsed.length
|
|
165
|
+
} hunks. ${this.getLengthOfHunks(parsed)} characters`
|
|
166
|
+
);
|
|
167
|
+
return parsed;
|
|
168
|
+
} catch (error) {
|
|
169
|
+
console.error(`GITHUB PLUGIN: Error parsing diff for ${url}:`, error.message);
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
144
172
|
})
|
|
145
173
|
);
|
|
146
174
|
}
|
|
@@ -153,30 +181,48 @@ export class GitHubPlugin extends PluginBase {
|
|
|
153
181
|
const urls = this.extractUrls(userPrompt);
|
|
154
182
|
|
|
155
183
|
if (urls) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
184
|
+
try {
|
|
185
|
+
const prs = [];
|
|
186
|
+
for (const url of urls) {
|
|
187
|
+
const prResponse = await this.getPR(url);
|
|
188
|
+
|
|
189
|
+
// Skip this PR if we couldn't get its data
|
|
190
|
+
if (!prResponse) {
|
|
191
|
+
console.log(`GITHUB PLUGIN: Skipping ${url} - could not fetch PR data`);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const { data: pr } = prResponse;
|
|
196
|
+
const responses = await this.getParsedDiffs([url]);
|
|
197
|
+
|
|
198
|
+
// Format the diffs in Markdown
|
|
199
|
+
const diffStrings = responses
|
|
200
|
+
.filter(response => response !== null)
|
|
201
|
+
.map(hunksToPatch);
|
|
202
|
+
|
|
203
|
+
prs.push({
|
|
204
|
+
description: pr.title,
|
|
205
|
+
url: pr.html_url,
|
|
206
|
+
body: pr.body,
|
|
207
|
+
author: pr.user.login,
|
|
208
|
+
diff: diffStrings,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (prs.length === 0) {
|
|
213
|
+
return "GITHUB PLUGIN: Could not fetch any pull request data. Please check your GITHUB_TOKEN and permissions.";
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const context = `GITHUB PLUGIN: These ${urls} have automatically been expanded to include the changes:\n\n${JSON.stringify(
|
|
217
|
+
prs,
|
|
218
|
+
null,
|
|
219
|
+
2
|
|
220
|
+
)}`;
|
|
221
|
+
console.log(context);
|
|
222
|
+
return context;
|
|
223
|
+
} catch (error) {
|
|
224
|
+
return `GITHUB PLUGIN: Error fetching pull request data: ${error.message}`;
|
|
171
225
|
}
|
|
172
|
-
|
|
173
|
-
const context = `GITHUB PLUGIN: These ${urls} have automatically been expanded to include the changes:\n\n${JSON.stringify(
|
|
174
|
-
prs,
|
|
175
|
-
null,
|
|
176
|
-
2
|
|
177
|
-
)}`;
|
|
178
|
-
console.log(context);
|
|
179
|
-
return context;
|
|
180
226
|
}
|
|
181
227
|
|
|
182
228
|
return "GITHUB PLUGIN: No pull request URLs detected.";
|
package/src/plugins/language.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { minimatch } from "minimatch";
|
|
|
3
3
|
import { EventService } from "../services/EventService";
|
|
4
4
|
import { Language } from "../types";
|
|
5
5
|
import { getConfig, getLanguageConfig } from "../config";
|
|
6
|
+
import { getEnabledPlugins } from "../types";
|
|
6
7
|
import { PluginBase, PluginMeta } from "./PluginBase";
|
|
7
8
|
import { Plugin, PluginContext } from "./types";
|
|
8
9
|
import { GitHubPlugin } from "./github";
|
|
@@ -115,7 +116,7 @@ export class LanguagePlugin extends PluginBase implements Plugin {
|
|
|
115
116
|
|
|
116
117
|
const plugins = this.context.Plugins.listPlugins();
|
|
117
118
|
for (const plugin of plugins) {
|
|
118
|
-
if (config.plugins.includes(plugin)) {
|
|
119
|
+
if (getEnabledPlugins(config.plugins).includes(plugin)) {
|
|
119
120
|
const matchingSources = sources.filter((s) => s.kind === plugin);
|
|
120
121
|
if (matchingSources.length === 0) {
|
|
121
122
|
continue;
|
|
@@ -258,15 +259,15 @@ export class LanguagePlugin extends PluginBase implements Plugin {
|
|
|
258
259
|
const terms = Object.keys(languageConfig);
|
|
259
260
|
|
|
260
261
|
// Find all matching terms in the userPrompt using glob patterns
|
|
261
|
-
const matchingTerms = terms.filter((term) =>
|
|
262
|
-
term.split(",").some((pattern) => {
|
|
262
|
+
const matchingTerms = terms.filter((term) => {
|
|
263
|
+
return term.split(",").some((pattern) => {
|
|
263
264
|
const trimmedPattern = pattern.trim();
|
|
264
|
-
// Use minimatch for
|
|
265
|
+
// Use minimatch for glob patterns, fallback to string contains for simple patterns
|
|
265
266
|
return trimmedPattern.includes("*")
|
|
266
267
|
? minimatch(userPrompt, trimmedPattern)
|
|
267
268
|
: userPrompt.toLowerCase().includes(trimmedPattern.toLowerCase());
|
|
268
|
-
})
|
|
269
|
-
);
|
|
269
|
+
});
|
|
270
|
+
});
|
|
270
271
|
return matchingTerms;
|
|
271
272
|
}
|
|
272
273
|
|
|
@@ -281,16 +282,13 @@ export class LanguagePlugin extends PluginBase implements Plugin {
|
|
|
281
282
|
// Use the extracted resolveSources method
|
|
282
283
|
const contexts = await this.resolveSources(matchingTerms);
|
|
283
284
|
|
|
284
|
-
if (!matchingTerms || !matchingTerms.length) {
|
|
285
|
-
return "LANGUAGE PLUGIN: No matching terms found";
|
|
286
|
-
}
|
|
287
|
-
|
|
288
285
|
console.log("LANGUAGE PLUGIN: Matching terms found:", matchingTerms);
|
|
289
286
|
|
|
287
|
+
const output = contexts.every((c) => typeof c === "string")
|
|
288
|
+
? contexts.join("")
|
|
289
|
+
: JSON.stringify(contexts, null, 2);
|
|
290
290
|
// Return the file contents in a format that can be added to the prompt context
|
|
291
|
-
return `LANGUAGE PLUGIN: The user mentioned these terms triggering contextual expansions ${matchingTerms} expanded to: ${
|
|
292
|
-
contexts
|
|
293
|
-
)}
|
|
291
|
+
return `LANGUAGE PLUGIN: The user mentioned these terms triggering contextual expansions ${matchingTerms} expanded to: ${output}
|
|
294
292
|
These terms are directly related to what the user is asking about so be sure to contextualize your response to this information.
|
|
295
293
|
`;
|
|
296
294
|
}
|
package/src/plugins/plugins.ts
CHANGED
|
@@ -12,6 +12,11 @@ import { DownloaderPlugin } from "./downloader/plugin";
|
|
|
12
12
|
import { FigmaPlugin } from "./figma";
|
|
13
13
|
import { UrlPlugin } from "./url";
|
|
14
14
|
import { GitPlugin } from "./GitPlugin";
|
|
15
|
+
import { TmuxPlugin } from "./tmux";
|
|
16
|
+
import { AgentsMdPlugin } from "./AgentsMdPlugin";
|
|
17
|
+
import { ExecPlugin } from "./exec";
|
|
18
|
+
import { getConfig } from "../config";
|
|
19
|
+
import { getDisabledPlugins } from "../types";
|
|
15
20
|
|
|
16
21
|
export class PluginService {
|
|
17
22
|
private pluginMap = new Map<string, Plugin>();
|
|
@@ -33,9 +38,9 @@ export class PluginService {
|
|
|
33
38
|
this.pluginMap.set("language", new LanguagePlugin(context));
|
|
34
39
|
this.pluginMap.set("url", new UrlPlugin(context));
|
|
35
40
|
this.pluginMap.set("git", new GitPlugin(context));
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
this.pluginMap.set("tmux", new TmuxPlugin(context));
|
|
42
|
+
this.pluginMap.set("agents-md", new AgentsMdPlugin(context));
|
|
43
|
+
this.pluginMap.set("exec", new ExecPlugin(context));
|
|
39
44
|
}
|
|
40
45
|
|
|
41
46
|
/* -------- lifecycle helpers ------------------------------------ */
|
|
@@ -96,7 +101,7 @@ export class PluginService {
|
|
|
96
101
|
return "";
|
|
97
102
|
}
|
|
98
103
|
const calls = plugins.map(async (p) => {
|
|
99
|
-
return this.
|
|
104
|
+
return this.callManyForPlugin(p, userInput).catch();
|
|
100
105
|
});
|
|
101
106
|
|
|
102
107
|
const results = await Promise.all(calls);
|
|
@@ -119,6 +124,22 @@ export class PluginService {
|
|
|
119
124
|
return newPlugin.call(userInput);
|
|
120
125
|
}
|
|
121
126
|
|
|
127
|
+
async callManyForPlugin(kind: string, userInput?: string) {
|
|
128
|
+
// Check new plugin system first
|
|
129
|
+
const newPlugin = this.pluginMap.get(kind);
|
|
130
|
+
|
|
131
|
+
if (!newPlugin) {
|
|
132
|
+
throw new Error(`Plugin ${kind} not found`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const enabled = await newPlugin.isEnabled();
|
|
136
|
+
if (!enabled) {
|
|
137
|
+
console.log(`Plugin ${kind} is disabled, skipping`);
|
|
138
|
+
return "";
|
|
139
|
+
}
|
|
140
|
+
return newPlugin.callMany(userInput);
|
|
141
|
+
}
|
|
142
|
+
|
|
122
143
|
async embed(kind: string, userInput: string) {
|
|
123
144
|
// Check new plugin system first
|
|
124
145
|
const newPlugin = this.pluginMap.get(kind);
|