@jmylchreest/aide-plugin 0.0.57 → 0.0.59
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 +5 -2
- package/src/cli/codex-config.ts +428 -0
- package/src/cli/hook.ts +85 -0
- package/src/cli/index.ts +49 -12
- package/src/cli/install.ts +52 -25
- package/src/cli/status.ts +50 -17
- package/src/cli/uninstall.ts +29 -8
- package/src/core/mcp-sync.ts +139 -17
- package/src/core/types.ts +2 -2
- package/src/hooks/agent-cleanup.ts +91 -0
- package/src/hooks/comment-checker.ts +115 -0
- package/src/hooks/context-guard.ts +115 -0
- package/src/hooks/context-pruning.ts +216 -0
- package/src/hooks/hud-updater.ts +180 -0
- package/src/hooks/permission-handler.ts +173 -0
- package/src/hooks/persistence.ts +93 -0
- package/src/hooks/pre-compact.ts +127 -0
- package/src/hooks/pre-tool-enforcer.ts +120 -0
- package/src/hooks/session-end.ts +148 -0
- package/src/hooks/session-start.ts +488 -0
- package/src/hooks/session-summary.ts +147 -0
- package/src/hooks/skill-injector.ts +235 -0
- package/src/hooks/subagent-tracker.ts +525 -0
- package/src/hooks/task-completed.ts +445 -0
- package/src/hooks/tool-tracker.ts +89 -0
- package/src/hooks/write-guard.ts +95 -0
- package/src/lib/aide-downloader.ts +58 -21
- package/src/lib/hook-utils.ts +53 -1
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Skill Injector Hook (UserPromptSubmit)
|
|
4
|
+
*
|
|
5
|
+
* Dynamically discovers and injects relevant skills based on prompt triggers.
|
|
6
|
+
* Searches both built-in skills and project-local .aide/skills/
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Recursive skill discovery
|
|
10
|
+
* - YAML frontmatter parsing for triggers
|
|
11
|
+
* - Caching with file watcher invalidation
|
|
12
|
+
* - Auto-creates .aide directories if needed
|
|
13
|
+
*
|
|
14
|
+
* Debug logging: Set AIDE_DEBUG=1 to enable tracing
|
|
15
|
+
* Logs written to: .aide/_logs/startup.log
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { existsSync, mkdirSync } from "fs";
|
|
19
|
+
import { join } from "path";
|
|
20
|
+
import { Logger, debug, setDebugCwd } from "../lib/logger.js";
|
|
21
|
+
import { readStdin, detectPlatform } from "../lib/hook-utils.js";
|
|
22
|
+
import {
|
|
23
|
+
discoverSkills as coreDiscoverSkills,
|
|
24
|
+
matchSkills as coreMatchSkills,
|
|
25
|
+
formatSkillsContext as coreFormatSkillsContext,
|
|
26
|
+
} from "../core/skill-matcher.js";
|
|
27
|
+
import type { Skill } from "../core/types.js";
|
|
28
|
+
|
|
29
|
+
const SOURCE = "skill-injector";
|
|
30
|
+
|
|
31
|
+
interface HookInput {
|
|
32
|
+
hook_event_name: string;
|
|
33
|
+
session_id: string;
|
|
34
|
+
cwd: string;
|
|
35
|
+
prompt?: string;
|
|
36
|
+
transcript_path?: string;
|
|
37
|
+
permission_mode?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface HookOutput {
|
|
41
|
+
continue: boolean;
|
|
42
|
+
hookSpecificOutput?: {
|
|
43
|
+
hookEventName: string;
|
|
44
|
+
additionalContext?: string;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Skill types, discovery, matching, and formatting are now in core
|
|
49
|
+
// Import aliases used below: coreDiscoverSkills, coreMatchSkills, coreFormatSkillsContext
|
|
50
|
+
|
|
51
|
+
// Module-level logger (initialized in main)
|
|
52
|
+
let log: Logger | null = null;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Ensure .aide directories exist (minimal version for skill-injector)
|
|
56
|
+
*/
|
|
57
|
+
function ensureDirectories(cwd: string): void {
|
|
58
|
+
const dirs = [
|
|
59
|
+
join(cwd, ".aide"),
|
|
60
|
+
join(cwd, ".aide", "skills"),
|
|
61
|
+
join(cwd, ".aide", "config"),
|
|
62
|
+
join(cwd, ".aide", "state"),
|
|
63
|
+
join(cwd, ".aide", "memory"),
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
for (const dir of dirs) {
|
|
67
|
+
if (!existsSync(dir)) {
|
|
68
|
+
try {
|
|
69
|
+
mkdirSync(dir, { recursive: true });
|
|
70
|
+
} catch (err) {
|
|
71
|
+
debugLog(`Failed to create directory ${dir}: ${err}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Discover all skills — delegates to core
|
|
79
|
+
*/
|
|
80
|
+
function discoverSkills(cwd: string): Skill[] {
|
|
81
|
+
log?.start("discoverSkills");
|
|
82
|
+
const pluginRoot =
|
|
83
|
+
process.env.AIDE_PLUGIN_ROOT || process.env.CLAUDE_PLUGIN_ROOT;
|
|
84
|
+
const skills = coreDiscoverSkills(cwd, pluginRoot || undefined);
|
|
85
|
+
log?.end("discoverSkills", { totalSkills: skills.length });
|
|
86
|
+
return skills;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Match skills to prompt — delegates to core
|
|
91
|
+
*/
|
|
92
|
+
function matchSkills(
|
|
93
|
+
prompt: string,
|
|
94
|
+
skills: Skill[],
|
|
95
|
+
maxResults = 3,
|
|
96
|
+
platform?: string,
|
|
97
|
+
): Skill[] {
|
|
98
|
+
log?.start("matchSkills");
|
|
99
|
+
const matched = coreMatchSkills(prompt, skills, maxResults, platform);
|
|
100
|
+
log?.end("matchSkills", { checked: skills.length, matched: matched.length });
|
|
101
|
+
return matched;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Format skills for injection — delegates to core
|
|
106
|
+
*/
|
|
107
|
+
function formatSkillsContext(skills: Skill[]): string {
|
|
108
|
+
return coreFormatSkillsContext(skills);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Debug helper - writes to debug.log (not stderr)
|
|
112
|
+
function debugLog(msg: string): void {
|
|
113
|
+
debug(SOURCE, msg);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Ensure we always output valid JSON, even on catastrophic errors
|
|
117
|
+
function outputContinue(): void {
|
|
118
|
+
try {
|
|
119
|
+
console.log(JSON.stringify({ continue: true }));
|
|
120
|
+
} catch {
|
|
121
|
+
// Last resort - raw JSON string
|
|
122
|
+
console.log('{"continue":true}');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Global error handlers to prevent hook crashes without JSON output
|
|
127
|
+
process.on("uncaughtException", (err) => {
|
|
128
|
+
debugLog(`UNCAUGHT EXCEPTION: ${err}`);
|
|
129
|
+
outputContinue();
|
|
130
|
+
process.exit(0);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
process.on("unhandledRejection", (reason) => {
|
|
134
|
+
debugLog(`UNHANDLED REJECTION: ${reason}`);
|
|
135
|
+
outputContinue();
|
|
136
|
+
process.exit(0);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
async function main(): Promise<void> {
|
|
140
|
+
const hookStart = Date.now();
|
|
141
|
+
debugLog(`Hook started at ${new Date().toISOString()}`);
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
debugLog("Reading stdin...");
|
|
145
|
+
const input = await readStdin();
|
|
146
|
+
debugLog(`Stdin read complete (${Date.now() - hookStart}ms)`);
|
|
147
|
+
|
|
148
|
+
if (!input.trim()) {
|
|
149
|
+
debugLog("Empty input, exiting");
|
|
150
|
+
console.log(JSON.stringify({ continue: true }));
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const data: HookInput = JSON.parse(input);
|
|
155
|
+
const prompt = data.prompt || "";
|
|
156
|
+
const cwd = data.cwd || process.cwd();
|
|
157
|
+
|
|
158
|
+
// Switch debug logging to project-local logs
|
|
159
|
+
setDebugCwd(cwd);
|
|
160
|
+
|
|
161
|
+
debugLog(`Parsed input: cwd=${cwd}, prompt=${prompt.length} chars`);
|
|
162
|
+
|
|
163
|
+
// Initialize logger
|
|
164
|
+
log = new Logger("skill-injector", cwd);
|
|
165
|
+
log.start("total");
|
|
166
|
+
log.debug(`Prompt length: ${prompt.length} chars`);
|
|
167
|
+
debugLog(`Logger initialized, enabled=${log.isEnabled()}`);
|
|
168
|
+
|
|
169
|
+
// Ensure .aide directories exist
|
|
170
|
+
debugLog("ensureDirectories starting...");
|
|
171
|
+
log.start("ensureDirectories");
|
|
172
|
+
ensureDirectories(cwd);
|
|
173
|
+
log.end("ensureDirectories");
|
|
174
|
+
debugLog(`ensureDirectories complete (${Date.now() - hookStart}ms)`);
|
|
175
|
+
|
|
176
|
+
if (!prompt) {
|
|
177
|
+
debugLog("No prompt provided, exiting");
|
|
178
|
+
log.info("No prompt provided");
|
|
179
|
+
log.end("total");
|
|
180
|
+
log.flush();
|
|
181
|
+
console.log(JSON.stringify({ continue: true }));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Discover and match skills
|
|
186
|
+
debugLog("discoverSkills starting...");
|
|
187
|
+
const skills = discoverSkills(cwd);
|
|
188
|
+
debugLog(
|
|
189
|
+
`discoverSkills complete: ${skills.length} skills (${Date.now() - hookStart}ms)`,
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
debugLog("matchSkills starting...");
|
|
193
|
+
const matched = matchSkills(prompt, skills, 3, detectPlatform());
|
|
194
|
+
debugLog(
|
|
195
|
+
`matchSkills complete: ${matched.length} matches (${Date.now() - hookStart}ms)`,
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
log.end("total");
|
|
199
|
+
|
|
200
|
+
if (matched.length > 0) {
|
|
201
|
+
log.info(
|
|
202
|
+
`Injecting ${matched.length} skills: ${matched.map((s) => s.name).join(", ")}`,
|
|
203
|
+
);
|
|
204
|
+
debugLog(`Flushing logs...`);
|
|
205
|
+
log.flush();
|
|
206
|
+
debugLog(`Hook complete (${Date.now() - hookStart}ms total)`);
|
|
207
|
+
|
|
208
|
+
const output: HookOutput = {
|
|
209
|
+
continue: true,
|
|
210
|
+
hookSpecificOutput: {
|
|
211
|
+
hookEventName: "UserPromptSubmit",
|
|
212
|
+
additionalContext: formatSkillsContext(matched),
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
console.log(JSON.stringify(output));
|
|
216
|
+
} else {
|
|
217
|
+
log.info("No matching skills");
|
|
218
|
+
debugLog(`Flushing logs...`);
|
|
219
|
+
log.flush();
|
|
220
|
+
debugLog(`Hook complete (${Date.now() - hookStart}ms total)`);
|
|
221
|
+
console.log(JSON.stringify({ continue: true }));
|
|
222
|
+
}
|
|
223
|
+
} catch (error) {
|
|
224
|
+
debugLog(`ERROR: ${error}`);
|
|
225
|
+
// Log error if logger is available
|
|
226
|
+
if (log) {
|
|
227
|
+
log.error("Skill injection failed", error);
|
|
228
|
+
log.flush();
|
|
229
|
+
}
|
|
230
|
+
// On error, allow continuation
|
|
231
|
+
console.log(JSON.stringify({ continue: true }));
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
main();
|