0xkobold 0.0.2 ā 0.0.4
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/README.md +59 -5
- package/dist/package.json +7 -5
- package/dist/src/cli/commands/setup.js +144 -0
- package/dist/src/cli/commands/setup.js.map +1 -0
- package/dist/src/cli/program.js +3 -0
- package/dist/src/cli/program.js.map +1 -1
- package/dist/src/extensions/core/auto-compact-on-error-extension.js +244 -0
- package/dist/src/extensions/core/auto-compact-on-error-extension.js.map +1 -0
- package/dist/src/extensions/core/diagnostics-extension.js +215 -0
- package/dist/src/extensions/core/diagnostics-extension.js.map +1 -0
- package/dist/src/extensions/core/extension-scaffold-extension.js +449 -0
- package/dist/src/extensions/core/extension-scaffold-extension.js.map +1 -0
- package/dist/src/extensions/core/git-commit-extension.js +527 -0
- package/dist/src/extensions/core/git-commit-extension.js.map +1 -0
- package/dist/src/extensions/core/heartbeat-extension.js +43 -0
- package/dist/src/extensions/core/heartbeat-extension.js.map +1 -1
- package/dist/src/extensions/core/memory-extension.js +120 -0
- package/dist/src/extensions/core/memory-extension.js.map +1 -0
- package/dist/src/extensions/core/memory-synthesis-extension.js +137 -0
- package/dist/src/extensions/core/memory-synthesis-extension.js.map +1 -0
- package/dist/src/extensions/core/mode-manager-extension.js +19 -0
- package/dist/src/extensions/core/mode-manager-extension.js.map +1 -1
- package/dist/src/extensions/core/ollama-cloud-extension.js +132 -0
- package/dist/src/extensions/core/ollama-cloud-extension.js.map +1 -0
- package/dist/src/extensions/core/ollama-router-extension.js +100 -0
- package/dist/src/extensions/core/ollama-router-extension.js.map +1 -0
- package/dist/src/extensions/core/perennial-memory-extension.js +449 -0
- package/dist/src/extensions/core/perennial-memory-extension.js.map +1 -0
- package/dist/src/index.js +7 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/llm/ollama.js +80 -9
- package/dist/src/llm/ollama.js.map +1 -1
- package/package.json +7 -5
- package/scripts/postinstall.js +71 -0
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Commit Extension for 0xKobold
|
|
3
|
+
*
|
|
4
|
+
* Provides conventional commit message generation and commit workflow.
|
|
5
|
+
* Based on: https://skills.sh/github/awesome-copilot/git-commit
|
|
6
|
+
*
|
|
7
|
+
* Official Skill: github/awesome-copilot - conventional-commit
|
|
8
|
+
*
|
|
9
|
+
* SAFETY PROTOCOLS:
|
|
10
|
+
* - NEVER update git config
|
|
11
|
+
* - NEVER run destructive commands (--force, hard reset) without explicit request
|
|
12
|
+
* - NEVER skip hooks (--no-verify) unless user asks
|
|
13
|
+
* - NEVER force push to main/master
|
|
14
|
+
* - If commit fails due to hooks, fix and create NEW commit (don't amend)
|
|
15
|
+
* - Never commit secrets (.env, credentials.json, private keys)
|
|
16
|
+
*/
|
|
17
|
+
import { execSync } from "child_process";
|
|
18
|
+
// Safety blocklist - files that should never be committed
|
|
19
|
+
const SECRET_PATTERNS = [
|
|
20
|
+
/\.env$/i,
|
|
21
|
+
/\.env\.local$/i,
|
|
22
|
+
/\.env\.production$/i,
|
|
23
|
+
/credentials/i,
|
|
24
|
+
/secret/i,
|
|
25
|
+
/private.*key/i,
|
|
26
|
+
/id_rsa/i,
|
|
27
|
+
/id_ed25519/i,
|
|
28
|
+
/\.pem$/i,
|
|
29
|
+
/\.key$/i,
|
|
30
|
+
/token/i,
|
|
31
|
+
/password/i,
|
|
32
|
+
];
|
|
33
|
+
/**
|
|
34
|
+
* Check if file might contain secrets
|
|
35
|
+
*/
|
|
36
|
+
function checkForSecrets(files) {
|
|
37
|
+
return files.filter(f => SECRET_PATTERNS.some(pattern => pattern.test(f)));
|
|
38
|
+
}
|
|
39
|
+
// Conventional commit types
|
|
40
|
+
const COMMIT_TYPES = [
|
|
41
|
+
{ type: "feat", desc: "A new feature" },
|
|
42
|
+
{ type: "fix", desc: "A bug fix" },
|
|
43
|
+
{ type: "docs", desc: "Documentation only changes" },
|
|
44
|
+
{ type: "style", desc: "Code style changes (formatting, semicolons, etc)" },
|
|
45
|
+
{ type: "refactor", desc: "Code refactoring without changing functionality" },
|
|
46
|
+
{ type: "perf", desc: "Performance improvements" },
|
|
47
|
+
{ type: "test", desc: "Adding or fixing tests" },
|
|
48
|
+
{ type: "build", desc: "Build system or dependency changes" },
|
|
49
|
+
{ type: "ci", desc: "CI/CD configuration changes" },
|
|
50
|
+
{ type: "chore", desc: "Other changes that don't modify src or test files" },
|
|
51
|
+
{ type: "revert", desc: "Reverting a previous commit" },
|
|
52
|
+
];
|
|
53
|
+
/**
|
|
54
|
+
* Get git status
|
|
55
|
+
*/
|
|
56
|
+
function getGitStatus() {
|
|
57
|
+
try {
|
|
58
|
+
const status = execSync("git status --porcelain", { encoding: "utf-8" });
|
|
59
|
+
const lines = status.trim().split("\n").filter(Boolean);
|
|
60
|
+
const staged = [];
|
|
61
|
+
const unstaged = [];
|
|
62
|
+
const untracked = [];
|
|
63
|
+
for (const line of lines) {
|
|
64
|
+
const stagedFlag = line[0];
|
|
65
|
+
const unstagedFlag = line[1];
|
|
66
|
+
const filename = line.slice(3).trim();
|
|
67
|
+
if (stagedFlag !== " " && stagedFlag !== "?") {
|
|
68
|
+
staged.push(filename);
|
|
69
|
+
}
|
|
70
|
+
if (unstagedFlag !== " ") {
|
|
71
|
+
unstaged.push(filename);
|
|
72
|
+
}
|
|
73
|
+
if (stagedFlag === "?") {
|
|
74
|
+
untracked.push(filename);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { staged, unstaged, untracked };
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
return { staged: [], unstaged: [], untracked: [] };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get git diff for staged files
|
|
85
|
+
*/
|
|
86
|
+
function getStagedDiff() {
|
|
87
|
+
try {
|
|
88
|
+
return execSync("git diff --cached", { encoding: "utf-8", maxBuffer: 1024 * 1024 });
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
return "";
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get git diff for unstaged files
|
|
96
|
+
*/
|
|
97
|
+
function getUnstagedDiff() {
|
|
98
|
+
try {
|
|
99
|
+
return execSync("git diff", { encoding: "utf-8", maxBuffer: 1024 * 1024 });
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
return "";
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Analyze changes and suggest commit type
|
|
107
|
+
*/
|
|
108
|
+
function suggestCommitType(files, diff) {
|
|
109
|
+
const fileStr = files.join(" ").toLowerCase();
|
|
110
|
+
const diffStr = diff.toLowerCase();
|
|
111
|
+
// Test files
|
|
112
|
+
if (fileStr.includes("test") || fileStr.includes("spec")) {
|
|
113
|
+
return "test";
|
|
114
|
+
}
|
|
115
|
+
// Documentation
|
|
116
|
+
if (fileStr.includes("readme") || fileStr.includes(".md") || fileStr.includes("docs/")) {
|
|
117
|
+
return "docs";
|
|
118
|
+
}
|
|
119
|
+
// Configuration/CI
|
|
120
|
+
if (fileStr.includes(".yml") || fileStr.includes(".yaml") || fileStr.includes(".json")) {
|
|
121
|
+
if (fileStr.includes(".github/") || fileStr.includes("workflow")) {
|
|
122
|
+
return "ci";
|
|
123
|
+
}
|
|
124
|
+
if (fileStr.includes("package.json") || fileStr.includes("tsconfig")) {
|
|
125
|
+
return "build";
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Check diff for patterns
|
|
129
|
+
if (diffStr.includes("delete") || diffStr.includes("remove")) {
|
|
130
|
+
// Could be refactor or chore
|
|
131
|
+
}
|
|
132
|
+
if (diffStr.includes("fix") || diffStr.includes("bug") || diffStr.includes("error")) {
|
|
133
|
+
return "fix";
|
|
134
|
+
}
|
|
135
|
+
if (diffStr.includes("feat") || diffStr.includes("add") || diffStr.includes("new")) {
|
|
136
|
+
return "feat";
|
|
137
|
+
}
|
|
138
|
+
if (diffStr.includes("perf") || diffStr.includes("optim")) {
|
|
139
|
+
return "perf";
|
|
140
|
+
}
|
|
141
|
+
if (diffStr.includes("refactor")) {
|
|
142
|
+
return "refactor";
|
|
143
|
+
}
|
|
144
|
+
return "feat"; // Default
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Parse commit message components
|
|
148
|
+
*/
|
|
149
|
+
function parseCommitMessage(input) {
|
|
150
|
+
// Match conventional commit pattern
|
|
151
|
+
const regex = /^(\w+)(?:\(([^)]+)\))?!?: (.+)$/m;
|
|
152
|
+
const match = input.match(regex);
|
|
153
|
+
if (match) {
|
|
154
|
+
const [, type, scope, description] = match;
|
|
155
|
+
const parts = input.split("\n\n");
|
|
156
|
+
const body = parts[1] || "";
|
|
157
|
+
const footer = parts[2] || "";
|
|
158
|
+
return { type, scope: scope || "", description, body, footer };
|
|
159
|
+
}
|
|
160
|
+
// Fallback: treat entire input as description
|
|
161
|
+
return { type: "", scope: "", description: input.trim(), body: "", footer: "" };
|
|
162
|
+
}
|
|
163
|
+
export default function gitCommitExtension(pi) {
|
|
164
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
165
|
+
// USER COMMANDS
|
|
166
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
167
|
+
pi.registerCommand("commit", {
|
|
168
|
+
description: "Generate conventional commit message (usage: /commit [message] or see status)",
|
|
169
|
+
handler: async (args, ctx) => {
|
|
170
|
+
const status = getGitStatus();
|
|
171
|
+
const { staged, unstaged, untracked } = status;
|
|
172
|
+
// If message provided and files staged, commit directly
|
|
173
|
+
if (args.trim() && staged.length > 0) {
|
|
174
|
+
const message = args.trim();
|
|
175
|
+
const { type, scope, description, body, footer } = parseCommitMessage(message);
|
|
176
|
+
if (!type || !COMMIT_TYPES.some(t => t.type === type)) {
|
|
177
|
+
ctx.ui?.notify?.("ā Invalid commit type. Use one of:\n" +
|
|
178
|
+
COMMIT_TYPES.map(t => ` ${t.type} - ${t.desc}`).join("\n"), "error");
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
const fullMessage = scope
|
|
183
|
+
? `${type}(${scope}): ${description}`
|
|
184
|
+
: `${type}: ${description}`;
|
|
185
|
+
const finalMessage = body ? `${fullMessage}\n\n${body}` : fullMessage;
|
|
186
|
+
const command = `git commit -m "${finalMessage.replace(/"/g, '\\"')}"`;
|
|
187
|
+
execSync(command, { encoding: "utf-8" });
|
|
188
|
+
ctx.ui?.notify?.(`ā
Committed: ${fullMessage}`, "info");
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
ctx.ui?.notify?.(`ā Commit failed: ${error}`, "error");
|
|
192
|
+
}
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
// Show status
|
|
196
|
+
let msg = "š Git Status:\n\n";
|
|
197
|
+
if (staged.length > 0) {
|
|
198
|
+
msg += `ā Staged (${staged.length}):\n${staged.map(f => ` ${f}`).join("\n")}\n\n`;
|
|
199
|
+
}
|
|
200
|
+
if (unstaged.length > 0) {
|
|
201
|
+
msg += `ā Unstaged (${unstaged.length}):\n${unstaged.map(f => ` ${f}`).join("\n")}\n\n`;
|
|
202
|
+
}
|
|
203
|
+
if (untracked.length > 0) {
|
|
204
|
+
msg += `? Untracked (${untracked.length}):\n${untracked.map(f => ` ${f}`).join("\n")}\n\n`;
|
|
205
|
+
}
|
|
206
|
+
if (staged.length === 0 && unstaged.length === 0 && untracked.length === 0) {
|
|
207
|
+
msg += "ā Working directory clean\n";
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
msg += "Use /commit-suggest to generate message\n";
|
|
211
|
+
msg += "Or /commit \"<type>(<scope>): <description>\" to commit";
|
|
212
|
+
}
|
|
213
|
+
ctx.ui.notify(msg, "info");
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
pi.registerCommand("commit-suggest", {
|
|
217
|
+
description: "Suggest conventional commit message based on staged changes",
|
|
218
|
+
handler: async (_args, ctx) => {
|
|
219
|
+
const status = getGitStatus();
|
|
220
|
+
const { staged } = status;
|
|
221
|
+
if (staged.length === 0) {
|
|
222
|
+
ctx.ui.notify("ā ļø No staged changes. Run 'git add <files>' first.", "warning");
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
const diff = getStagedDiff();
|
|
226
|
+
const suggestedType = suggestCommitType(staged, diff);
|
|
227
|
+
// Try to infer scope from file paths
|
|
228
|
+
const dirs = staged.map(f => f.split("/")[0]).filter(Boolean);
|
|
229
|
+
const scope = dirs.length === 1 ? dirs[0] : "";
|
|
230
|
+
// Generate description from file changes
|
|
231
|
+
const fileNames = staged.map(f => f.split("/").pop()?.replace(/\.[^.]+$/, ""));
|
|
232
|
+
const description = staged.length === 1
|
|
233
|
+
? `update ${fileNames[0]}`
|
|
234
|
+
: `update ${staged.length} files`;
|
|
235
|
+
const commitMsg = scope
|
|
236
|
+
? `${suggestedType}(${scope}): ${description}`
|
|
237
|
+
: `${suggestedType}: ${description}`;
|
|
238
|
+
ctx.ui.notify(`š” Suggested commit message:\n\n` +
|
|
239
|
+
` ${commitMsg}\n\n` +
|
|
240
|
+
`Type: ${suggestedType} (${COMMIT_TYPES.find(t => t.type === suggestedType)?.desc})\n` +
|
|
241
|
+
`Files: ${staged.join(", ")}\n\n` +
|
|
242
|
+
`To commit: /commit \"${commitMsg}\"`, "info");
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
pi.registerCommand("commit-types", {
|
|
246
|
+
description: "Show conventional commit types",
|
|
247
|
+
handler: async (_args, ctx) => {
|
|
248
|
+
const types = COMMIT_TYPES.map(t => ` ${t.type.padEnd(10)} - ${t.desc}`).join("\n");
|
|
249
|
+
ctx.ui.notify(`š Conventional Commit Types:\n\n${types}\n\n` +
|
|
250
|
+
`Format: type(scope): description\n` +
|
|
251
|
+
`Example: feat(auth): add OAuth login`, "info");
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
pi.registerCommand("commit-amend", {
|
|
255
|
+
description: "Amend last commit (usage: /commit-amend [new-message])",
|
|
256
|
+
handler: async (args, ctx) => {
|
|
257
|
+
try {
|
|
258
|
+
if (args.trim()) {
|
|
259
|
+
// Amend with new message
|
|
260
|
+
execSync(`git commit --amend -m "${args.replace(/"/g, '\\"')}"`, { encoding: "utf-8" });
|
|
261
|
+
ctx.ui.notify("ā
Commit amended with new message", "info");
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
// Amend without changing message
|
|
265
|
+
execSync("git commit --amend --no-edit", { encoding: "utf-8" });
|
|
266
|
+
ctx.ui.notify("ā
Commit amended (files added, message unchanged)", "info");
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
ctx.ui.notify(`ā Amend failed: ${error}`, "error");
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
pi.registerCommand("commit-last", {
|
|
275
|
+
description: "Show last commit",
|
|
276
|
+
handler: async (_args, ctx) => {
|
|
277
|
+
try {
|
|
278
|
+
const lastCommit = execSync("git log -1 --format='%h %s'", { encoding: "utf-8" }).trim();
|
|
279
|
+
const lastCommitFull = execSync("git log -1 --format='%H%n%an <%ae>%n%ad%n%n%s%n%n%b'", { encoding: "utf-8" }).trim();
|
|
280
|
+
ctx.ui.notify(`š Last commit:\n ${lastCommit}\n\n${lastCommitFull}`, "info");
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
ctx.ui.notify("ā Failed to get last commit", "error");
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
});
|
|
287
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
288
|
+
// AGENT TOOLS
|
|
289
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
290
|
+
pi.registerTool({
|
|
291
|
+
name: "git_status",
|
|
292
|
+
label: "git_status",
|
|
293
|
+
description: "Get current git status including staged, unstaged, and untracked files. Use before generating commit messages.",
|
|
294
|
+
// @ts-ignore TSchema mismatch
|
|
295
|
+
parameters: {
|
|
296
|
+
type: "object",
|
|
297
|
+
properties: {},
|
|
298
|
+
},
|
|
299
|
+
async execute(_toolCallId, _params, _signal, _onUpdate, _ctx) {
|
|
300
|
+
const status = getGitStatus();
|
|
301
|
+
const { staged, unstaged, untracked } = status;
|
|
302
|
+
const summary = [];
|
|
303
|
+
if (staged.length > 0)
|
|
304
|
+
summary.push(`${staged.length} staged`);
|
|
305
|
+
if (unstaged.length > 0)
|
|
306
|
+
summary.push(`${unstaged.length} unstaged`);
|
|
307
|
+
if (untracked.length > 0)
|
|
308
|
+
summary.push(`${untracked.length} untracked`);
|
|
309
|
+
const summaryStr = summary.length > 0 ? summary.join(", ") : "clean";
|
|
310
|
+
return {
|
|
311
|
+
content: [{
|
|
312
|
+
type: "text",
|
|
313
|
+
text: `Git status: ${summaryStr}\n\n` +
|
|
314
|
+
(staged.length > 0 ? `Staged:\n${staged.map(f => ` - ${f}`).join("\n")}\n\n` : "") +
|
|
315
|
+
(unstaged.length > 0 ? `Unstaged:\n${unstaged.map(f => ` - ${f}`).join("\n")}\n\n` : "") +
|
|
316
|
+
(untracked.length > 0 ? `Untracked:\n${untracked.map(f => ` - ${f}`).join("\n")}` : "")
|
|
317
|
+
}],
|
|
318
|
+
details: { success: true, ...status },
|
|
319
|
+
};
|
|
320
|
+
},
|
|
321
|
+
});
|
|
322
|
+
pi.registerTool({
|
|
323
|
+
name: "git_diff",
|
|
324
|
+
label: "git_diff",
|
|
325
|
+
description: "Get git diff for staged or unstaged changes. Use to understand what changed before generating commit messages.",
|
|
326
|
+
// @ts-ignore TSchema mismatch
|
|
327
|
+
parameters: {
|
|
328
|
+
type: "object",
|
|
329
|
+
properties: {
|
|
330
|
+
staged: {
|
|
331
|
+
type: "boolean",
|
|
332
|
+
description: "Get diff for staged changes (default: true)",
|
|
333
|
+
default: true,
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
338
|
+
const { staged = true } = params;
|
|
339
|
+
const diff = staged ? getStagedDiff() : getUnstagedDiff();
|
|
340
|
+
const lines = diff.split("\n").length;
|
|
341
|
+
const truncated = diff.length > 8000 ? diff.slice(0, 8000) + "\n\n... (truncated)" : diff;
|
|
342
|
+
return {
|
|
343
|
+
content: [{
|
|
344
|
+
type: "text",
|
|
345
|
+
text: diff ? `Diff (${lines} lines):\n\n\`\`\`diff\n${truncated}\n\`\`\`` : "No changes"
|
|
346
|
+
}],
|
|
347
|
+
details: { success: true, lineCount: lines, charCount: diff.length },
|
|
348
|
+
};
|
|
349
|
+
},
|
|
350
|
+
});
|
|
351
|
+
pi.registerTool({
|
|
352
|
+
name: "generate_commit_message",
|
|
353
|
+
label: "generate_commit_message",
|
|
354
|
+
description: "Generate a conventional commit message based on staged changes. Analyzes git status and diff to suggest type, scope, and description.",
|
|
355
|
+
// @ts-ignore TSchema mismatch
|
|
356
|
+
parameters: {
|
|
357
|
+
type: "object",
|
|
358
|
+
properties: {
|
|
359
|
+
custom_scope: {
|
|
360
|
+
type: "string",
|
|
361
|
+
description: "Optional custom scope to override auto-detection",
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
366
|
+
const { custom_scope } = params;
|
|
367
|
+
const status = getGitStatus();
|
|
368
|
+
const { staged } = status;
|
|
369
|
+
if (staged.length === 0) {
|
|
370
|
+
return {
|
|
371
|
+
content: [{ type: "text", text: "No staged changes. Run 'git add' first." }],
|
|
372
|
+
details: { success: false, reason: "no_staged_changes" },
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
const diff = getStagedDiff();
|
|
376
|
+
const suggestedType = suggestCommitType(staged, diff);
|
|
377
|
+
// Determine scope
|
|
378
|
+
let scope = custom_scope || "";
|
|
379
|
+
if (!scope) {
|
|
380
|
+
const dirs = staged.map(f => f.split("/")[0]).filter(Boolean);
|
|
381
|
+
const uniqueDirs = [...new Set(dirs)];
|
|
382
|
+
if (uniqueDirs.length === 1) {
|
|
383
|
+
scope = uniqueDirs[0];
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
// Generate description
|
|
387
|
+
const fileNames = staged
|
|
388
|
+
.map(f => f.split("/").pop()?.replace(/\.[^.]+$/, ""))
|
|
389
|
+
.filter(Boolean);
|
|
390
|
+
let description = "";
|
|
391
|
+
if (staged.length === 1) {
|
|
392
|
+
const file = staged[0].split("/").pop() || staged[0];
|
|
393
|
+
const action = suggestedType === "fix" ? "fix" : suggestedType === "feat" ? "add" : "update";
|
|
394
|
+
description = `${action} ${file}`;
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
const action = suggestedType === "fix" ? "fix" : suggestedType === "feat" ? "add" : "update";
|
|
398
|
+
description = `${action} ${staged.length} files`;
|
|
399
|
+
}
|
|
400
|
+
const commitMsg = scope
|
|
401
|
+
? `${suggestedType}(${scope}): ${description}`
|
|
402
|
+
: `${suggestedType}: ${description}`;
|
|
403
|
+
const typeInfo = COMMIT_TYPES.find(t => t.type === suggestedType);
|
|
404
|
+
return {
|
|
405
|
+
content: [{
|
|
406
|
+
type: "text",
|
|
407
|
+
text: `Suggested commit message:\n\n` +
|
|
408
|
+
`\`\`\`\n${commitMsg}\n\`\`\`\n\n` +
|
|
409
|
+
`Type: ${suggestedType} - ${typeInfo?.desc}\n` +
|
|
410
|
+
`Scope: ${scope || "(none)"}\n` +
|
|
411
|
+
`Files: ${staged.join(", ")}`
|
|
412
|
+
}],
|
|
413
|
+
details: {
|
|
414
|
+
success: true,
|
|
415
|
+
message: commitMsg,
|
|
416
|
+
type: suggestedType,
|
|
417
|
+
scope,
|
|
418
|
+
description,
|
|
419
|
+
files: staged,
|
|
420
|
+
},
|
|
421
|
+
};
|
|
422
|
+
},
|
|
423
|
+
});
|
|
424
|
+
pi.registerTool({
|
|
425
|
+
name: "commit_changes",
|
|
426
|
+
label: "commit_changes",
|
|
427
|
+
description: "Commit staged changes with a conventional commit message. SAFETY: Never commits secrets, never uses --no-verify or force flags.",
|
|
428
|
+
// @ts-ignore TSchema mismatch
|
|
429
|
+
parameters: {
|
|
430
|
+
type: "object",
|
|
431
|
+
properties: {
|
|
432
|
+
message: {
|
|
433
|
+
type: "string",
|
|
434
|
+
description: "Commit message (format: type(scope): description)",
|
|
435
|
+
},
|
|
436
|
+
body: {
|
|
437
|
+
type: "string",
|
|
438
|
+
description: "Optional commit body (additional paragraphs)",
|
|
439
|
+
},
|
|
440
|
+
footer: {
|
|
441
|
+
type: "string",
|
|
442
|
+
description: "Optional footer (e.g., BREAKING CHANGE: ..., Fixes #123)",
|
|
443
|
+
},
|
|
444
|
+
},
|
|
445
|
+
required: ["message"],
|
|
446
|
+
},
|
|
447
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
448
|
+
const { message, body, footer } = params;
|
|
449
|
+
const status = getGitStatus();
|
|
450
|
+
if (status.staged.length === 0) {
|
|
451
|
+
return {
|
|
452
|
+
content: [{ type: "text", text: "No staged changes to commit." }],
|
|
453
|
+
details: { success: false, reason: "no_staged_changes" },
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
// SAFETY CHECK: Never commit secrets
|
|
457
|
+
const secrets = checkForSecrets(status.staged);
|
|
458
|
+
if (secrets.length > 0) {
|
|
459
|
+
const warning = `ā ļø POTENTIAL SECRETS DETECTED:\n${secrets.map(s => ` - ${s}`).join("\n")}\n\n` +
|
|
460
|
+
`These files may contain sensitive data. Use .gitignore to exclude them.`;
|
|
461
|
+
return {
|
|
462
|
+
content: [{ type: "text", text: warning }],
|
|
463
|
+
details: { success: false, reason: "secrets_detected", files: secrets },
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
// Validate message format
|
|
467
|
+
const match = message.match(/^(\w+)(?:\(([^)]+)\))?!?: (.+)$/);
|
|
468
|
+
if (!match) {
|
|
469
|
+
return {
|
|
470
|
+
content: [{
|
|
471
|
+
type: "text",
|
|
472
|
+
text: "Invalid commit message format. Use: type(scope): description\n\n" +
|
|
473
|
+
"Examples:\n" +
|
|
474
|
+
" feat(auth): add login\n" +
|
|
475
|
+
" fix: correct typo\n" +
|
|
476
|
+
" docs: update README"
|
|
477
|
+
}],
|
|
478
|
+
details: { success: false, reason: "invalid_format" },
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
const [, type, , description] = match;
|
|
482
|
+
if (!COMMIT_TYPES.some(t => t.type === type)) {
|
|
483
|
+
return {
|
|
484
|
+
content: [{
|
|
485
|
+
type: "text",
|
|
486
|
+
text: `Invalid commit type: "${type}". Use one of:\n` +
|
|
487
|
+
COMMIT_TYPES.map(t => ` ${t.type} - ${t.desc}`).join("\n")
|
|
488
|
+
}],
|
|
489
|
+
details: { success: false, reason: "invalid_type", validTypes: COMMIT_TYPES.map(t => t.type) },
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
try {
|
|
493
|
+
// Build full message
|
|
494
|
+
let fullMessage = message;
|
|
495
|
+
if (body) {
|
|
496
|
+
fullMessage += "\n\n" + body;
|
|
497
|
+
}
|
|
498
|
+
if (footer) {
|
|
499
|
+
fullMessage += "\n\n" + footer;
|
|
500
|
+
}
|
|
501
|
+
// SAFETY: Never use --no-verify, always let hooks run
|
|
502
|
+
const command = `git commit -m "${fullMessage.replace(/"/g, '\"')}"`;
|
|
503
|
+
const result = execSync(command, { encoding: "utf-8" });
|
|
504
|
+
if (ctx.ui?.notify) {
|
|
505
|
+
ctx.ui.notify(`ā
Committed: ${message}`, "info");
|
|
506
|
+
}
|
|
507
|
+
return {
|
|
508
|
+
content: [{ type: "text", text: `Committed successfully:\n ${message}\n\n${result}` }],
|
|
509
|
+
details: { success: true, message, command },
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
catch (error) {
|
|
513
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
514
|
+
// If hooks failed, advise creating new commit rather than amending
|
|
515
|
+
const advice = errorMsg.includes("hook")
|
|
516
|
+
? "\n\nš” Pre-commit hooks failed. Fix the issues and create a new commit (don't amend)."
|
|
517
|
+
: "";
|
|
518
|
+
return {
|
|
519
|
+
content: [{ type: "text", text: `Commit failed: ${errorMsg}${advice}` }],
|
|
520
|
+
details: { success: false, error: errorMsg, hooksFailed: errorMsg.includes("hook") },
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
},
|
|
524
|
+
});
|
|
525
|
+
console.log("[GitCommit] Extension loaded - /commit, /commit-suggest, /commit-types");
|
|
526
|
+
}
|
|
527
|
+
//# sourceMappingURL=git-commit-extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-commit-extension.js","sourceRoot":"","sources":["../../../../src/extensions/core/git-commit-extension.ts"],"names":[],"mappings":"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"}
|
|
@@ -336,6 +336,49 @@ If something needs attention ā brief alert message (no HEARTBEAT_OK token)
|
|
|
336
336
|
},
|
|
337
337
|
});
|
|
338
338
|
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
339
|
+
// HEALTH CHECK COMMAND (for VPS deployment)
|
|
340
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
341
|
+
pi.registerCommand("healthz", {
|
|
342
|
+
description: "Health check endpoint for VPS/container monitoring",
|
|
343
|
+
handler: async (_args, ctx) => {
|
|
344
|
+
const uptime = process.uptime();
|
|
345
|
+
const memory = process.memoryUsage();
|
|
346
|
+
const now = new Date().toISOString();
|
|
347
|
+
const status = {
|
|
348
|
+
status: "healthy",
|
|
349
|
+
timestamp: now,
|
|
350
|
+
uptime: `${Math.floor(uptime / 86400)}d ${Math.floor((uptime % 86400) / 3600)}h ${Math.floor((uptime % 3600) / 60)}m ${Math.floor(uptime % 60)}s`,
|
|
351
|
+
uptimeSeconds: Math.floor(uptime),
|
|
352
|
+
version: process.env.npm_package_version || "0.0.3",
|
|
353
|
+
extensions: {
|
|
354
|
+
heartbeat: {
|
|
355
|
+
enabled: config.enabled,
|
|
356
|
+
interval: config.every,
|
|
357
|
+
lastCheck: lastHeartbeat ? new Date(lastHeartbeat).toISOString() : null
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
memory: {
|
|
361
|
+
heapUsed: Math.round(memory.heapUsed / 1024 / 1024) + " MB",
|
|
362
|
+
heapTotal: Math.round(memory.heapTotal / 1024 / 1024) + " MB",
|
|
363
|
+
rss: Math.round(memory.rss / 1024 / 1024) + " MB"
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
// Return JSON for programmatic access
|
|
367
|
+
ctx.ui.notify(JSON.stringify(status, null, 2), "info");
|
|
368
|
+
},
|
|
369
|
+
});
|
|
370
|
+
// Also register /health as alias
|
|
371
|
+
pi.registerCommand("health", {
|
|
372
|
+
description: "Health check (alias for /healthz)",
|
|
373
|
+
handler: async (_args, ctx) => {
|
|
374
|
+
// Forward to healthz
|
|
375
|
+
const healthzCmd = pi.getCommands?.()?.find((c) => c.name === "healthz");
|
|
376
|
+
if (healthzCmd) {
|
|
377
|
+
await healthzCmd.handler("", ctx);
|
|
378
|
+
}
|
|
379
|
+
},
|
|
380
|
+
});
|
|
381
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
339
382
|
// AUTO-HEARTBEAT SCHEDULER
|
|
340
383
|
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
341
384
|
pi.on("session_start", async () => {
|