@tyvm/knowhow 0.0.83 → 0.0.84
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/package.json +4 -2
- package/src/agents/base/base.ts +72 -62
- package/src/agents/index.ts +30 -14
- package/src/agents/tools/startAgentTask.ts +3 -1
- package/src/chat/CliChatService.ts +20 -4
- package/src/chat/modules/AgentModule.ts +399 -357
- package/src/chat/modules/CustomCommandsModule.ts +0 -1
- package/src/chat/modules/InternalChatModule.ts +18 -2
- package/src/chat/modules/RendererModule.ts +109 -0
- package/src/chat/modules/SessionsModule.ts +854 -0
- package/src/chat/modules/SetupModule.ts +6 -8
- package/src/chat/modules/index.ts +1 -0
- package/src/chat/renderer/CompactRenderer.ts +209 -0
- package/src/chat/renderer/ConsoleRenderer.ts +141 -0
- package/src/chat/renderer/FancyRenderer.ts +421 -0
- package/src/chat/renderer/index.ts +5 -0
- package/src/chat/renderer/loadRenderer.ts +314 -0
- package/src/chat/renderer/messagesToRenderEvents.ts +96 -0
- package/src/chat/renderer/types.ts +88 -0
- package/src/chat/types.ts +5 -0
- package/src/chat.ts +69 -5
- package/src/cli.ts +24 -5
- package/src/config.ts +15 -0
- package/src/plugins/AgentsMdPlugin.ts +1 -1
- package/src/plugins/GitPlugin.ts +20 -20
- package/src/plugins/PluginBase.ts +11 -0
- package/src/plugins/SkillsPlugin.ts +150 -0
- package/src/plugins/asana.ts +4 -4
- package/src/plugins/embedding.ts +3 -5
- package/src/plugins/exec.ts +3 -3
- package/src/plugins/figma.ts +3 -7
- package/src/plugins/github.ts +18 -29
- package/src/plugins/jira.ts +2 -2
- package/src/plugins/language.ts +4 -4
- package/src/plugins/linear.ts +4 -4
- package/src/plugins/notion.ts +6 -8
- package/src/plugins/plugins.ts +29 -3
- package/src/plugins/url.ts +2 -2
- package/src/plugins/vim.ts +4 -3
- package/src/services/AgentService.ts +17 -0
- package/src/services/AgentSyncFs.ts +3 -0
- package/src/services/EventService.ts +168 -27
- package/src/services/KnowhowClient.ts +1 -0
- package/src/services/SessionManager.ts +51 -1
- package/src/services/SyncedAgentWatcher.ts +397 -0
- package/src/services/SyncerService.ts +147 -0
- package/src/services/index.ts +2 -0
- package/src/services/modules/index.ts +14 -3
- package/src/types.ts +25 -0
- package/src/worker.ts +80 -2
- package/src/workers/auth/PasskeySetup.ts +185 -0
- package/src/workers/auth/WorkerPasskeyAuth.ts +190 -0
- package/src/workers/auth/types.ts +58 -0
- package/src/workers/tools/getChallenge.ts +33 -0
- package/src/workers/tools/index.ts +8 -0
- package/src/workers/tools/lock.ts +31 -0
- package/src/workers/tools/unlock.ts +116 -0
- package/tests/unit/modules/moduleLoading.test.ts +226 -0
- package/tests/unit/plugins/pluginLoading.test.ts +151 -0
- package/ts_build/package.json +4 -2
- package/ts_build/src/agents/base/base.d.ts +4 -3
- package/ts_build/src/agents/base/base.js +54 -30
- package/ts_build/src/agents/base/base.js.map +1 -1
- package/ts_build/src/agents/index.d.ts +3 -0
- package/ts_build/src/agents/index.js +21 -11
- package/ts_build/src/agents/index.js.map +1 -1
- package/ts_build/src/agents/tools/startAgentTask.js +2 -1
- package/ts_build/src/agents/tools/startAgentTask.js.map +1 -1
- package/ts_build/src/chat/CliChatService.js +16 -5
- package/ts_build/src/chat/CliChatService.js.map +1 -1
- package/ts_build/src/chat/modules/AgentModule.d.ts +34 -17
- package/ts_build/src/chat/modules/AgentModule.js +248 -258
- package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
- package/ts_build/src/chat/modules/CustomCommandsModule.js.map +1 -1
- package/ts_build/src/chat/modules/InternalChatModule.d.ts +3 -0
- package/ts_build/src/chat/modules/InternalChatModule.js +16 -1
- package/ts_build/src/chat/modules/InternalChatModule.js.map +1 -1
- package/ts_build/src/chat/modules/RendererModule.d.ts +16 -0
- package/ts_build/src/chat/modules/RendererModule.js +76 -0
- package/ts_build/src/chat/modules/RendererModule.js.map +1 -0
- package/ts_build/src/chat/modules/SessionsModule.d.ts +33 -0
- package/ts_build/src/chat/modules/SessionsModule.js +582 -0
- package/ts_build/src/chat/modules/SessionsModule.js.map +1 -0
- package/ts_build/src/chat/modules/SetupModule.d.ts +3 -3
- package/ts_build/src/chat/modules/SetupModule.js +4 -6
- package/ts_build/src/chat/modules/SetupModule.js.map +1 -1
- 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/renderer/CompactRenderer.d.ts +23 -0
- package/ts_build/src/chat/renderer/CompactRenderer.js +167 -0
- package/ts_build/src/chat/renderer/CompactRenderer.js.map +1 -0
- package/ts_build/src/chat/renderer/ConsoleRenderer.d.ts +22 -0
- package/ts_build/src/chat/renderer/ConsoleRenderer.js +110 -0
- package/ts_build/src/chat/renderer/ConsoleRenderer.js.map +1 -0
- package/ts_build/src/chat/renderer/FancyRenderer.d.ts +23 -0
- package/ts_build/src/chat/renderer/FancyRenderer.js +328 -0
- package/ts_build/src/chat/renderer/FancyRenderer.js.map +1 -0
- package/ts_build/src/chat/renderer/index.d.ts +5 -0
- package/ts_build/src/chat/renderer/index.js +29 -0
- package/ts_build/src/chat/renderer/index.js.map +1 -0
- package/ts_build/src/chat/renderer/loadRenderer.d.ts +4 -0
- package/ts_build/src/chat/renderer/loadRenderer.js +246 -0
- package/ts_build/src/chat/renderer/loadRenderer.js.map +1 -0
- package/ts_build/src/chat/renderer/messagesToRenderEvents.d.ts +15 -0
- package/ts_build/src/chat/renderer/messagesToRenderEvents.js +72 -0
- package/ts_build/src/chat/renderer/messagesToRenderEvents.js.map +1 -0
- package/ts_build/src/chat/renderer/types.d.ts +75 -0
- package/ts_build/src/chat/renderer/types.js +3 -0
- package/ts_build/src/chat/renderer/types.js.map +1 -0
- package/ts_build/src/chat/types.d.ts +5 -0
- package/ts_build/src/chat.js +46 -4
- package/ts_build/src/chat.js.map +1 -1
- package/ts_build/src/cli.js +18 -5
- package/ts_build/src/cli.js.map +1 -1
- package/ts_build/src/config.d.ts +1 -0
- package/ts_build/src/config.js +17 -1
- package/ts_build/src/config.js.map +1 -1
- package/ts_build/src/plugins/AgentsMdPlugin.js +1 -1
- package/ts_build/src/plugins/AgentsMdPlugin.js.map +1 -1
- package/ts_build/src/plugins/GitPlugin.js +20 -20
- package/ts_build/src/plugins/GitPlugin.js.map +1 -1
- package/ts_build/src/plugins/PluginBase.d.ts +1 -0
- package/ts_build/src/plugins/PluginBase.js +13 -0
- package/ts_build/src/plugins/PluginBase.js.map +1 -1
- package/ts_build/src/plugins/SkillsPlugin.d.ts +13 -0
- package/ts_build/src/plugins/SkillsPlugin.js +149 -0
- package/ts_build/src/plugins/SkillsPlugin.js.map +1 -0
- package/ts_build/src/plugins/asana.js +4 -4
- package/ts_build/src/plugins/asana.js.map +1 -1
- package/ts_build/src/plugins/embedding.js +3 -3
- package/ts_build/src/plugins/embedding.js.map +1 -1
- package/ts_build/src/plugins/exec.js +3 -3
- package/ts_build/src/plugins/exec.js.map +1 -1
- package/ts_build/src/plugins/figma.js +3 -3
- package/ts_build/src/plugins/figma.js.map +1 -1
- package/ts_build/src/plugins/github.js +18 -18
- package/ts_build/src/plugins/github.js.map +1 -1
- package/ts_build/src/plugins/jira.js +2 -2
- package/ts_build/src/plugins/jira.js.map +1 -1
- package/ts_build/src/plugins/language.js +4 -4
- package/ts_build/src/plugins/language.js.map +1 -1
- package/ts_build/src/plugins/linear.js +4 -4
- package/ts_build/src/plugins/linear.js.map +1 -1
- package/ts_build/src/plugins/notion.js +6 -6
- package/ts_build/src/plugins/notion.js.map +1 -1
- package/ts_build/src/plugins/plugins.d.ts +3 -0
- package/ts_build/src/plugins/plugins.js +18 -3
- package/ts_build/src/plugins/plugins.js.map +1 -1
- package/ts_build/src/plugins/url.js +2 -2
- package/ts_build/src/plugins/url.js.map +1 -1
- package/ts_build/src/plugins/vim.js +2 -2
- package/ts_build/src/plugins/vim.js.map +1 -1
- package/ts_build/src/services/AgentService.d.ts +3 -0
- package/ts_build/src/services/AgentService.js +7 -0
- package/ts_build/src/services/AgentService.js.map +1 -1
- package/ts_build/src/services/AgentSyncFs.d.ts +1 -0
- package/ts_build/src/services/AgentSyncFs.js +2 -0
- package/ts_build/src/services/AgentSyncFs.js.map +1 -1
- package/ts_build/src/services/EventService.d.ts +25 -2
- package/ts_build/src/services/EventService.js +92 -14
- package/ts_build/src/services/EventService.js.map +1 -1
- package/ts_build/src/services/KnowhowClient.d.ts +1 -0
- package/ts_build/src/services/KnowhowClient.js.map +1 -1
- package/ts_build/src/services/SessionManager.d.ts +6 -0
- package/ts_build/src/services/SessionManager.js +39 -1
- package/ts_build/src/services/SessionManager.js.map +1 -1
- package/ts_build/src/services/SyncedAgentWatcher.d.ts +101 -0
- package/ts_build/src/services/SyncedAgentWatcher.js +312 -0
- package/ts_build/src/services/SyncedAgentWatcher.js.map +1 -0
- package/ts_build/src/services/SyncerService.d.ts +30 -0
- package/ts_build/src/services/SyncerService.js +72 -0
- package/ts_build/src/services/SyncerService.js.map +1 -0
- package/ts_build/src/services/index.d.ts +2 -0
- package/ts_build/src/services/index.js +2 -0
- package/ts_build/src/services/index.js.map +1 -1
- package/ts_build/src/services/modules/index.js +10 -2
- package/ts_build/src/services/modules/index.js.map +1 -1
- package/ts_build/src/types.d.ts +19 -0
- package/ts_build/src/types.js.map +1 -1
- package/ts_build/src/worker.d.ts +2 -0
- package/ts_build/src/worker.js +59 -4
- package/ts_build/src/worker.js.map +1 -1
- package/ts_build/src/workers/auth/PasskeySetup.d.ts +10 -0
- package/ts_build/src/workers/auth/PasskeySetup.js +131 -0
- package/ts_build/src/workers/auth/PasskeySetup.js.map +1 -0
- package/ts_build/src/workers/auth/WorkerPasskeyAuth.d.ts +35 -0
- package/ts_build/src/workers/auth/WorkerPasskeyAuth.js +129 -0
- package/ts_build/src/workers/auth/WorkerPasskeyAuth.js.map +1 -0
- package/ts_build/src/workers/auth/types.d.ts +36 -0
- package/ts_build/src/workers/auth/types.js +3 -0
- package/ts_build/src/workers/auth/types.js.map +1 -0
- package/ts_build/src/workers/tools/getChallenge.d.ts +9 -0
- package/ts_build/src/workers/tools/getChallenge.js +27 -0
- package/ts_build/src/workers/tools/getChallenge.js.map +1 -0
- package/ts_build/src/workers/tools/index.d.ts +6 -0
- package/ts_build/src/workers/tools/index.js +10 -0
- package/ts_build/src/workers/tools/index.js.map +1 -1
- package/ts_build/src/workers/tools/lock.d.ts +9 -0
- package/ts_build/src/workers/tools/lock.js +27 -0
- package/ts_build/src/workers/tools/lock.js.map +1 -0
- package/ts_build/src/workers/tools/unlock.d.ts +18 -0
- package/ts_build/src/workers/tools/unlock.js +78 -0
- package/ts_build/src/workers/tools/unlock.js.map +1 -0
- package/ts_build/tests/unit/modules/moduleLoading.test.d.ts +1 -0
- package/ts_build/tests/unit/modules/moduleLoading.test.js +187 -0
- package/ts_build/tests/unit/modules/moduleLoading.test.js.map +1 -0
- package/ts_build/tests/unit/plugins/pluginLoading.test.d.ts +1 -0
- package/ts_build/tests/unit/plugins/pluginLoading.test.js +123 -0
- package/ts_build/tests/unit/plugins/pluginLoading.test.js.map +1 -0
package/src/cli.ts
CHANGED
|
@@ -35,6 +35,7 @@ import { BaseAgent } from "./agents/base/base";
|
|
|
35
35
|
import { AskModule } from "./chat/modules/AskModule";
|
|
36
36
|
import { SearchModule } from "./chat/modules/SearchModule";
|
|
37
37
|
import { AgentModule } from "./chat/modules/AgentModule";
|
|
38
|
+
import { SessionsModule } from "./chat/modules/SessionsModule";
|
|
38
39
|
import { readPromptFile } from "./ai";
|
|
39
40
|
import { SetupModule } from "./chat/modules/SetupModule";
|
|
40
41
|
import { CliChatService } from "./chat/CliChatService";
|
|
@@ -48,22 +49,32 @@ async function setupServices() {
|
|
|
48
49
|
...OldTools.getContext(),
|
|
49
50
|
});
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
// Build the AgentContext with the fully-populated LazyToolsService so every
|
|
53
|
+
// agent created (including those in setupAgent) gets all tools registered.
|
|
54
|
+
const agentContext: import("./agents/base/base").AgentContext = {
|
|
52
55
|
...services(),
|
|
53
56
|
Tools,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const { Researcher, Developer, Patcher, Setup } = agents({
|
|
60
|
+
...agentContext,
|
|
54
61
|
});
|
|
55
62
|
|
|
56
63
|
Agents.registerAgent(Researcher);
|
|
57
64
|
Agents.registerAgent(Patcher);
|
|
58
65
|
Agents.registerAgent(Developer);
|
|
59
66
|
Agents.registerAgent(Setup);
|
|
60
|
-
Agents.loadAgentsFromConfig(
|
|
67
|
+
Agents.loadAgentsFromConfig(agentContext);
|
|
61
68
|
|
|
62
69
|
Tools.defineTools(includedTools, allTools);
|
|
63
70
|
|
|
64
71
|
// Add Mcp service to tool context directly so MCP management tools can access it
|
|
65
72
|
Tools.addContext("Mcp", Mcp);
|
|
66
73
|
|
|
74
|
+
// Store the fully-wired AgentContext on AgentService so AgentModule.setupAgent
|
|
75
|
+
// can retrieve it when creating fresh agent instances via createAgent().
|
|
76
|
+
Agents.setAgentContext(agentContext);
|
|
77
|
+
|
|
67
78
|
console.log("🔌 Connecting to MCP...");
|
|
68
79
|
await Mcp.connectToConfigured(Tools);
|
|
69
80
|
console.log("Connecting to clients...");
|
|
@@ -322,7 +333,9 @@ async function main() {
|
|
|
322
333
|
.action(async (options) => {
|
|
323
334
|
try {
|
|
324
335
|
await setupServices();
|
|
325
|
-
const
|
|
336
|
+
const agentModule = new AgentModule();
|
|
337
|
+
await agentModule.initialize(chatService);
|
|
338
|
+
const setupModule = new SetupModule(agentModule);
|
|
326
339
|
await setupModule.initialize(chatService);
|
|
327
340
|
await setupModule.handleSetupCommand([]);
|
|
328
341
|
} catch (error) {
|
|
@@ -367,11 +380,15 @@ async function main() {
|
|
|
367
380
|
program
|
|
368
381
|
.command("sessions")
|
|
369
382
|
.description("Manage agent sessions from CLI")
|
|
370
|
-
.
|
|
383
|
+
.option("--all", "Show all historical sessions (default: current process only)")
|
|
384
|
+
.option("--csv", "Output sessions as CSV")
|
|
385
|
+
.action(async (options) => {
|
|
371
386
|
try {
|
|
372
387
|
const agentModule = new AgentModule();
|
|
373
388
|
await agentModule.initialize(chatService);
|
|
374
|
-
|
|
389
|
+
const sessionsModule = new SessionsModule(agentModule);
|
|
390
|
+
await sessionsModule.initialize(chatService);
|
|
391
|
+
await sessionsModule.logSessionTable(options.all || false, options.csv || false, true);
|
|
375
392
|
} catch (error) {
|
|
376
393
|
console.error("Error listing sessions:", error);
|
|
377
394
|
process.exit(1);
|
|
@@ -394,6 +411,8 @@ async function main() {
|
|
|
394
411
|
"--no-sandbox",
|
|
395
412
|
"Run worker directly on host (disable sandbox mode)"
|
|
396
413
|
)
|
|
414
|
+
.option("--passkey", "Set up passkey authentication for this worker")
|
|
415
|
+
.option("--passkey-reset", "Remove passkey authentication requirement")
|
|
397
416
|
.action(async (options) => {
|
|
398
417
|
await setupServices();
|
|
399
418
|
await worker(options);
|
package/src/config.ts
CHANGED
|
@@ -262,6 +262,21 @@ export async function getConfig() {
|
|
|
262
262
|
}
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
+
export async function getGlobalConfig(): Promise<Config> {
|
|
266
|
+
const globalConfigDir = getGlobalConfigDir();
|
|
267
|
+
const globalConfigPath = path.join(globalConfigDir, "knowhow.json");
|
|
268
|
+
if (!fs.existsSync(globalConfigPath)) {
|
|
269
|
+
return {} as Config;
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
const config = await readFile(globalConfigPath, "utf8");
|
|
273
|
+
return JSON.parse(config) as Config;
|
|
274
|
+
} catch (error) {
|
|
275
|
+
console.warn("Failed to load global knowhow config:", error);
|
|
276
|
+
return {} as Config;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
265
280
|
export async function migrateConfig() {
|
|
266
281
|
// Apply migrations, used to keep config structure up to date.
|
|
267
282
|
if (!fs.existsSync(".knowhow/knowhow.json")) {
|
|
@@ -98,7 +98,7 @@ export class AgentsMdPlugin extends PluginBase implements Plugin {
|
|
|
98
98
|
|
|
99
99
|
events.emit("agent:msg", alertMessage);
|
|
100
100
|
} catch (error) {
|
|
101
|
-
|
|
101
|
+
this.log("AGENTS-MD PLUGIN: Error handling file event: " + error, "error");
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|
package/src/plugins/GitPlugin.ts
CHANGED
|
@@ -110,7 +110,7 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
110
110
|
|
|
111
111
|
await this.setBranch("main");
|
|
112
112
|
} catch (error) {
|
|
113
|
-
|
|
113
|
+
this.log(`Failed to initialize .knowhow git repository: ${error}`, "error");
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
|
|
@@ -144,7 +144,7 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
144
144
|
try {
|
|
145
145
|
return this.gitCommand(command, options);
|
|
146
146
|
} catch (error) {
|
|
147
|
-
|
|
147
|
+
this.log(`Safe git command failed: ${command} - ${error}`, "warn");
|
|
148
148
|
return null;
|
|
149
149
|
}
|
|
150
150
|
}
|
|
@@ -235,7 +235,7 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
235
235
|
|
|
236
236
|
// Get the current HEAD commit hash from the actual repo (if it exists)
|
|
237
237
|
const actualRepoHash = this.getRepoHash();
|
|
238
|
-
|
|
238
|
+
this.log(`Current branch is ${this.getCurrentBranch()}`);
|
|
239
239
|
|
|
240
240
|
// First, handle any uncommitted changes on the current branch
|
|
241
241
|
const hasChanges = await this.hasChanges();
|
|
@@ -246,7 +246,7 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
246
246
|
: `sync ${new Date().toISOString()}`;
|
|
247
247
|
await this.commitAll(message);
|
|
248
248
|
} catch (error) {
|
|
249
|
-
|
|
249
|
+
this.log(`Failed to commit uncommitted changes: ${error}`, "error");
|
|
250
250
|
}
|
|
251
251
|
}
|
|
252
252
|
|
|
@@ -259,7 +259,7 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
259
259
|
|
|
260
260
|
await this.setBranch("main");
|
|
261
261
|
} catch (error) {
|
|
262
|
-
|
|
262
|
+
this.log(`Failed to ensure clean state: ${error}`, "error");
|
|
263
263
|
}
|
|
264
264
|
}
|
|
265
265
|
|
|
@@ -288,7 +288,7 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
288
288
|
this.gitCommand(`checkout -b ${branchName}`);
|
|
289
289
|
}
|
|
290
290
|
} catch (error) {
|
|
291
|
-
|
|
291
|
+
this.log(`Failed to set branch ${branchName}`, "error");
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
294
|
|
|
@@ -298,7 +298,7 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
298
298
|
try {
|
|
299
299
|
this.gitCommand(`checkout -b ${branchName}`);
|
|
300
300
|
} catch (error) {
|
|
301
|
-
|
|
301
|
+
this.log(`Failed to create branch ${branchName}`, "error");
|
|
302
302
|
}
|
|
303
303
|
}
|
|
304
304
|
|
|
@@ -317,7 +317,7 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
317
317
|
try {
|
|
318
318
|
this.gitCommand(`add "${file}"`);
|
|
319
319
|
} catch (error) {
|
|
320
|
-
|
|
320
|
+
this.log(`Failed to add file ${file}: ${error}`, "warn");
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
323
|
} else {
|
|
@@ -339,7 +339,7 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
339
339
|
this.gitCommand("add -A");
|
|
340
340
|
await this.commitWithEvents(message);
|
|
341
341
|
} catch (error) {
|
|
342
|
-
|
|
342
|
+
this.log(`Failed to commit all changes: ${error}`, "error");
|
|
343
343
|
}
|
|
344
344
|
}
|
|
345
345
|
|
|
@@ -389,7 +389,7 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
389
389
|
`
|
|
390
390
|
);
|
|
391
391
|
} catch (error) {
|
|
392
|
-
|
|
392
|
+
this.log(`Failed to commit with events: ${error}`, "error");
|
|
393
393
|
}
|
|
394
394
|
}
|
|
395
395
|
|
|
@@ -402,7 +402,7 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
402
402
|
try {
|
|
403
403
|
this.gitCommand('commit --allow-empty -m "Initial empty commit"');
|
|
404
404
|
} catch (error) {
|
|
405
|
-
|
|
405
|
+
this.log(`Could not create initial commit: ${error}`, "warn");
|
|
406
406
|
}
|
|
407
407
|
}
|
|
408
408
|
}
|
|
@@ -424,7 +424,7 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
424
424
|
|
|
425
425
|
await this.commitAll(message);
|
|
426
426
|
} catch (error) {
|
|
427
|
-
|
|
427
|
+
this.log(`Auto-commit failed: ${error}`, "error");
|
|
428
428
|
}
|
|
429
429
|
}
|
|
430
430
|
|
|
@@ -455,9 +455,9 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
455
455
|
);
|
|
456
456
|
}
|
|
457
457
|
|
|
458
|
-
|
|
458
|
+
this.log(`Created new task branch: ${branchName}`);
|
|
459
459
|
} catch (error) {
|
|
460
|
-
|
|
460
|
+
this.log(`Failed to handle new task: ${error}`, "error");
|
|
461
461
|
}
|
|
462
462
|
}
|
|
463
463
|
|
|
@@ -466,7 +466,7 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
466
466
|
|
|
467
467
|
try {
|
|
468
468
|
if (!this.currentTask) {
|
|
469
|
-
|
|
469
|
+
this.log("No tasks in progress to complete", "warn");
|
|
470
470
|
return;
|
|
471
471
|
}
|
|
472
472
|
|
|
@@ -488,7 +488,7 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
488
488
|
// Clear current task
|
|
489
489
|
this.currentTask = null;
|
|
490
490
|
} catch (error) {
|
|
491
|
-
|
|
491
|
+
this.log(`Failed to handle task completion: ${error}`, "error");
|
|
492
492
|
}
|
|
493
493
|
}
|
|
494
494
|
|
|
@@ -523,9 +523,9 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
523
523
|
try {
|
|
524
524
|
const noteMessage = `[Build Stable] No linting issues found on branch: ${this.getCurrentBranch()}`;
|
|
525
525
|
this.gitCommand(`notes add -f -m "${noteMessage}" ${commitHash}`);
|
|
526
|
-
|
|
526
|
+
this.log(`Marked commit ${commitHash} as build stable`);
|
|
527
527
|
} catch (error) {
|
|
528
|
-
|
|
528
|
+
this.log(`Failed to add git note for commit ${commitHash}: ${error}`, "warn");
|
|
529
529
|
}
|
|
530
530
|
}
|
|
531
531
|
|
|
@@ -559,7 +559,7 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
559
559
|
.map((line) => line.replace(/^\*?\s*/, "").trim())
|
|
560
560
|
.filter((line) => line.length > 0);
|
|
561
561
|
} catch (error) {
|
|
562
|
-
|
|
562
|
+
this.log(`Error getting branches: ${error}`, "error");
|
|
563
563
|
return [];
|
|
564
564
|
}
|
|
565
565
|
}
|
|
@@ -592,7 +592,7 @@ Your modifications are automatically tracked separately and won't affect the use
|
|
|
592
592
|
this.commitAll(message);
|
|
593
593
|
}
|
|
594
594
|
} catch (error) {
|
|
595
|
-
|
|
595
|
+
this.log(`Failed to merge ${branchName}: ${error}`, "error");
|
|
596
596
|
}
|
|
597
597
|
}
|
|
598
598
|
}
|
|
@@ -43,6 +43,17 @@ export abstract class PluginBase implements Plugin {
|
|
|
43
43
|
return true; // subclasses override if needed
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
protected log(message: string, level: "info" | "warn" | "error" = "info"): void {
|
|
47
|
+
if (this.context.Events) {
|
|
48
|
+
this.context.Events.log(this.meta.name, message, level);
|
|
49
|
+
} else {
|
|
50
|
+
// Fallback to console if no Events service
|
|
51
|
+
if (level === "error") console.error(`[${this.meta.name}] ${message}`);
|
|
52
|
+
else if (level === "warn") console.warn(`[${this.meta.name}] ${message}`);
|
|
53
|
+
else console.log(`[${this.meta.name}] ${message}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
46
57
|
/* ------------------------------------------------------------------ */
|
|
47
58
|
/** Default callMany implementation - delegates to call ------------ */
|
|
48
59
|
/* ------------------------------------------------------------------ */
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { promises as fs, Dirent } 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
|
+
import { getConfig } from "../config";
|
|
7
|
+
|
|
8
|
+
interface SkillMeta {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
filePath: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function parseFrontmatter(content: string): Record<string, string> {
|
|
15
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
16
|
+
if (!match) return {};
|
|
17
|
+
const result: Record<string, string> = {};
|
|
18
|
+
for (const line of match[1].split("\n")) {
|
|
19
|
+
const [key, ...rest] = line.split(":");
|
|
20
|
+
if (key && rest.length) result[key.trim()] = rest.join(":").trim();
|
|
21
|
+
}
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class SkillsPlugin extends PluginBase implements Plugin {
|
|
26
|
+
static readonly meta: PluginMeta = {
|
|
27
|
+
key: "skills",
|
|
28
|
+
name: "Skills Plugin",
|
|
29
|
+
description:
|
|
30
|
+
"Scans configured skills directories for SKILL.md files and provides skill content to agents",
|
|
31
|
+
requires: [],
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
meta = SkillsPlugin.meta;
|
|
35
|
+
|
|
36
|
+
constructor(context: PluginContext) {
|
|
37
|
+
super(context);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async call(input?: string): Promise<string> {
|
|
41
|
+
const result = await this.embed(input || "");
|
|
42
|
+
return result.map((e) => e.text).join("\n\n");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async embed(userPrompt: string): Promise<MinimalEmbedding[]> {
|
|
46
|
+
const config = await getConfig();
|
|
47
|
+
const skillDirs: string[] = (config as any).skills || [];
|
|
48
|
+
|
|
49
|
+
if (skillDirs.length === 0) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const skills = await this.scanSkills(skillDirs);
|
|
54
|
+
|
|
55
|
+
if (skills.length === 0) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Check if any skill name appears in the prompt
|
|
60
|
+
const matchedSkills = skills.filter((skill) =>
|
|
61
|
+
userPrompt.toLowerCase().includes(skill.name.toLowerCase())
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
if (matchedSkills.length > 0) {
|
|
65
|
+
// Return full skill content for matched skills
|
|
66
|
+
const results: MinimalEmbedding[] = [];
|
|
67
|
+
for (const skill of matchedSkills) {
|
|
68
|
+
try {
|
|
69
|
+
const content = await fs.readFile(skill.filePath, "utf-8");
|
|
70
|
+
results.push({
|
|
71
|
+
id: skill.filePath,
|
|
72
|
+
text: `## Skill: ${skill.name}\nFile: ${skill.filePath}\n\n${content}`,
|
|
73
|
+
metadata: { filePath: skill.filePath },
|
|
74
|
+
});
|
|
75
|
+
} catch {
|
|
76
|
+
// Skip unreadable files
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return results;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Return skill discovery summary
|
|
83
|
+
const summary = this.buildSkillSummary(skills);
|
|
84
|
+
return [
|
|
85
|
+
{
|
|
86
|
+
id: "skills:summary",
|
|
87
|
+
text: summary,
|
|
88
|
+
metadata: {},
|
|
89
|
+
},
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private async scanSkills(dirs: string[]): Promise<SkillMeta[]> {
|
|
94
|
+
const skills: SkillMeta[] = [];
|
|
95
|
+
for (const dir of dirs) {
|
|
96
|
+
const resolvedDir = dir.replace(/^~/, process.env.HOME || "");
|
|
97
|
+
try {
|
|
98
|
+
const found = await this.findSkillFiles(resolvedDir);
|
|
99
|
+
skills.push(...found);
|
|
100
|
+
} catch {
|
|
101
|
+
// Skip directories that don't exist or can't be read
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return skills;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private async findSkillFiles(dir: string): Promise<SkillMeta[]> {
|
|
108
|
+
const skills: SkillMeta[] = [];
|
|
109
|
+
let entries: Dirent[];
|
|
110
|
+
try {
|
|
111
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
112
|
+
} catch {
|
|
113
|
+
return skills;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
for (const entry of entries) {
|
|
117
|
+
const fullPath = path.join(dir, entry.name);
|
|
118
|
+
if (entry.isDirectory()) {
|
|
119
|
+
const nested = await this.findSkillFiles(fullPath);
|
|
120
|
+
skills.push(...nested);
|
|
121
|
+
} else if (entry.isFile() && entry.name === "SKILL.md") {
|
|
122
|
+
try {
|
|
123
|
+
const content = await fs.readFile(fullPath, "utf-8");
|
|
124
|
+
const frontmatter = parseFrontmatter(content);
|
|
125
|
+
const name = frontmatter.name;
|
|
126
|
+
const description = frontmatter.description || "";
|
|
127
|
+
if (name) {
|
|
128
|
+
skills.push({ name, description, filePath: fullPath });
|
|
129
|
+
}
|
|
130
|
+
} catch {
|
|
131
|
+
// Skip unreadable files
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return skills;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private buildSkillSummary(skills: SkillMeta[]): string {
|
|
140
|
+
const lines = ["Available skills:"];
|
|
141
|
+
for (const skill of skills) {
|
|
142
|
+
lines.push(`- ${skill.name} (${skill.filePath}): ${skill.description}`);
|
|
143
|
+
}
|
|
144
|
+
lines.push("");
|
|
145
|
+
lines.push(
|
|
146
|
+
"To use a skill, reference its name in your request and I will load the full instructions."
|
|
147
|
+
);
|
|
148
|
+
return lines.join("\n");
|
|
149
|
+
}
|
|
150
|
+
}
|
package/src/plugins/asana.ts
CHANGED
|
@@ -57,7 +57,7 @@ export class AsanaPlugin extends PluginBase {
|
|
|
57
57
|
});
|
|
58
58
|
|
|
59
59
|
const allTasks = tasksEmbeddings.concat(projectTaskEmbeddings);
|
|
60
|
-
|
|
60
|
+
this.log(`Found ${allTasks.length} tasks`);
|
|
61
61
|
return allTasks;
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -92,7 +92,7 @@ export class AsanaPlugin extends PluginBase {
|
|
|
92
92
|
async getTasksFromProjectUrl(url: string) {
|
|
93
93
|
const urlParts = url.split("/");
|
|
94
94
|
const projectId = urlParts[4];
|
|
95
|
-
|
|
95
|
+
this.log(`Project ID: ${projectId}`);
|
|
96
96
|
if (!projectId) {
|
|
97
97
|
return null;
|
|
98
98
|
}
|
|
@@ -113,7 +113,7 @@ export class AsanaPlugin extends PluginBase {
|
|
|
113
113
|
async getTaskFromUrl(url: string) {
|
|
114
114
|
const taskId = url.split("/").pop();
|
|
115
115
|
if (taskId) {
|
|
116
|
-
|
|
116
|
+
this.log(`Fetching Asana task ${taskId}`);
|
|
117
117
|
return await this.getTaskData(taskId);
|
|
118
118
|
}
|
|
119
119
|
return null;
|
|
@@ -124,7 +124,7 @@ export class AsanaPlugin extends PluginBase {
|
|
|
124
124
|
const task = await this.asanaClient.tasks.findById(taskId);
|
|
125
125
|
return task;
|
|
126
126
|
} catch (error) {
|
|
127
|
-
|
|
127
|
+
this.log(`Error fetching Asana task: ${error}`, "error");
|
|
128
128
|
return null;
|
|
129
129
|
}
|
|
130
130
|
}
|
package/src/plugins/embedding.ts
CHANGED
|
@@ -41,7 +41,7 @@ export class EmbeddingPlugin extends PluginBase {
|
|
|
41
41
|
cwd: process.cwd(),
|
|
42
42
|
});
|
|
43
43
|
child.unref();
|
|
44
|
-
|
|
44
|
+
this.log(`Started 'knowhow embed' in background (pid: ${child.pid})`);
|
|
45
45
|
return "Embedding started in background process";
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -65,13 +65,11 @@ export class EmbeddingPlugin extends PluginBase {
|
|
|
65
65
|
pruneMetadata(context);
|
|
66
66
|
|
|
67
67
|
for (const entry of context) {
|
|
68
|
-
|
|
68
|
+
this.log(`Reading entry ${entry.id}`);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
const contextLength = JSON.stringify(context).split(" ").length;
|
|
72
|
-
|
|
73
|
-
`EMBEDDING PLUGIN: Found ${context.length} entries. Loading ${contextLength} words`
|
|
74
|
-
);
|
|
72
|
+
this.log(`Found ${context.length} entries. Loading ${contextLength} words`);
|
|
75
73
|
|
|
76
74
|
return `EMBEDDING PLUGIN: Our knowledgebase contains this information which can be used to answer the question:
|
|
77
75
|
${JSON.stringify(context)}`;
|
package/src/plugins/exec.ts
CHANGED
|
@@ -40,7 +40,7 @@ export class ExecPlugin extends PluginBase {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
try {
|
|
43
|
-
|
|
43
|
+
this.log(`Executing: ${command}`);
|
|
44
44
|
|
|
45
45
|
// Execute the command
|
|
46
46
|
const result = execSync(command, {
|
|
@@ -55,9 +55,9 @@ export class ExecPlugin extends PluginBase {
|
|
|
55
55
|
const stderr = error.stderr || "";
|
|
56
56
|
const stdout = error.stdout || "";
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
this.log(`Command failed: ${errorMessage}`, "error");
|
|
59
59
|
if (stderr) {
|
|
60
|
-
|
|
60
|
+
this.log(stderr, "error");
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
return `EXEC PLUGIN: Command \`${command}\` failed:\n\`\`\`\n${stdout}\n${stderr}\n${errorMessage}\n\`\`\``;
|
package/src/plugins/figma.ts
CHANGED
|
@@ -64,11 +64,11 @@ export class FigmaPlugin extends PluginBase implements Plugin {
|
|
|
64
64
|
return null;
|
|
65
65
|
}
|
|
66
66
|
try {
|
|
67
|
-
|
|
67
|
+
this.log(`Fetching figma data: ${JSON.stringify({ fileId, nodeIds })}`);
|
|
68
68
|
const response = await this.client.fileImages(fileId, { ids: nodeIds });
|
|
69
69
|
return { id: fileId, ...response.data };
|
|
70
70
|
} catch (error) {
|
|
71
|
-
|
|
71
|
+
this.log(`Error fetching Figma file data: ${error}`, "error");
|
|
72
72
|
return null;
|
|
73
73
|
}
|
|
74
74
|
}
|
|
@@ -146,11 +146,7 @@ export class FigmaPlugin extends PluginBase implements Plugin {
|
|
|
146
146
|
imageUrl,
|
|
147
147
|
`Describe the image with relavant information for this user question: ${userPrompt}`
|
|
148
148
|
);
|
|
149
|
-
|
|
150
|
-
console.log(
|
|
151
|
-
"FIGMA PLUGIN: Image description",
|
|
152
|
-
imageDescription.choices[0].message.content
|
|
153
|
-
);
|
|
149
|
+
this.log(`Image description: ${imageDescription.choices[0].message.content}`);
|
|
154
150
|
responses.push({ nodeId, imageDescription });
|
|
155
151
|
}
|
|
156
152
|
}
|