@compilr-dev/agents-coding 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +788 -0
  2. package/dist/index.d.ts +39 -0
  3. package/dist/index.js +75 -0
  4. package/dist/skills/index.d.ts +39 -0
  5. package/dist/skills/index.js +322 -0
  6. package/dist/tools/git/branch.d.ts +17 -0
  7. package/dist/tools/git/branch.js +264 -0
  8. package/dist/tools/git/commit.d.ts +23 -0
  9. package/dist/tools/git/commit.js +280 -0
  10. package/dist/tools/git/diff.d.ts +19 -0
  11. package/dist/tools/git/diff.js +221 -0
  12. package/dist/tools/git/index.d.ts +10 -0
  13. package/dist/tools/git/index.js +11 -0
  14. package/dist/tools/git/log.d.ts +19 -0
  15. package/dist/tools/git/log.js +235 -0
  16. package/dist/tools/git/stash.d.ts +17 -0
  17. package/dist/tools/git/stash.js +294 -0
  18. package/dist/tools/git/status.d.ts +19 -0
  19. package/dist/tools/git/status.js +160 -0
  20. package/dist/tools/git/types.d.ts +293 -0
  21. package/dist/tools/git/types.js +4 -0
  22. package/dist/tools/git/utils.d.ts +58 -0
  23. package/dist/tools/git/utils.js +197 -0
  24. package/dist/tools/index.d.ts +5 -0
  25. package/dist/tools/index.js +5 -0
  26. package/dist/tools/project/detect.d.ts +19 -0
  27. package/dist/tools/project/detect.js +341 -0
  28. package/dist/tools/project/find-root.d.ts +21 -0
  29. package/dist/tools/project/find-root.js +239 -0
  30. package/dist/tools/project/index.d.ts +6 -0
  31. package/dist/tools/project/index.js +5 -0
  32. package/dist/tools/project/types.d.ts +83 -0
  33. package/dist/tools/project/types.js +4 -0
  34. package/dist/tools/runners/build.d.ts +19 -0
  35. package/dist/tools/runners/build.js +306 -0
  36. package/dist/tools/runners/format.d.ts +19 -0
  37. package/dist/tools/runners/format.js +376 -0
  38. package/dist/tools/runners/index.d.ts +9 -0
  39. package/dist/tools/runners/index.js +9 -0
  40. package/dist/tools/runners/lint.d.ts +19 -0
  41. package/dist/tools/runners/lint.js +356 -0
  42. package/dist/tools/runners/test.d.ts +19 -0
  43. package/dist/tools/runners/test.js +386 -0
  44. package/dist/tools/runners/types.d.ts +97 -0
  45. package/dist/tools/runners/types.js +4 -0
  46. package/dist/tools/runners/utils.d.ts +69 -0
  47. package/dist/tools/runners/utils.js +179 -0
  48. package/dist/tools/search/definition.d.ts +19 -0
  49. package/dist/tools/search/definition.js +305 -0
  50. package/dist/tools/search/index.d.ts +8 -0
  51. package/dist/tools/search/index.js +8 -0
  52. package/dist/tools/search/references.d.ts +19 -0
  53. package/dist/tools/search/references.js +179 -0
  54. package/dist/tools/search/todos.d.ts +19 -0
  55. package/dist/tools/search/todos.js +269 -0
  56. package/dist/tools/search/types.d.ts +132 -0
  57. package/dist/tools/search/types.js +4 -0
  58. package/dist/tools/search/utils.d.ts +45 -0
  59. package/dist/tools/search/utils.js +152 -0
  60. package/package.json +88 -0
@@ -0,0 +1,294 @@
1
+ /**
2
+ * Git Stash Tool
3
+ * Stash and restore changes
4
+ */
5
+ import { defineTool, createSuccessResult, createErrorResult } from '@compilr-dev/agents';
6
+ import { runGitCommand, isGitRepository, isDirectory } from './utils.js';
7
+ /**
8
+ * Git stash tool
9
+ */
10
+ export const gitStashTool = defineTool({
11
+ name: 'git_stash',
12
+ description: 'Manage git stashes. Actions: push (save changes), pop (apply and remove), ' +
13
+ 'apply (apply without removing), list (show all stashes), drop (remove stash), ' +
14
+ 'clear (remove all stashes), show (display stash contents).',
15
+ inputSchema: {
16
+ type: 'object',
17
+ properties: {
18
+ path: {
19
+ type: 'string',
20
+ description: 'Working directory path (default: current directory)',
21
+ },
22
+ action: {
23
+ type: 'string',
24
+ enum: ['push', 'pop', 'apply', 'list', 'drop', 'clear', 'show'],
25
+ description: 'Action to perform',
26
+ },
27
+ message: {
28
+ type: 'string',
29
+ description: 'Stash message (for push action)',
30
+ },
31
+ includeUntracked: {
32
+ type: 'boolean',
33
+ description: 'Include untracked files (for push action)',
34
+ },
35
+ index: {
36
+ type: 'number',
37
+ description: 'Stash index (for pop/apply/drop/show, default: 0)',
38
+ },
39
+ },
40
+ required: ['action'],
41
+ },
42
+ execute: executeGitStash,
43
+ });
44
+ /**
45
+ * Execute git stash
46
+ */
47
+ async function executeGitStash(input) {
48
+ const targetPath = input.path ?? process.cwd();
49
+ // Check if path exists
50
+ if (!(await isDirectory(targetPath))) {
51
+ return createErrorResult(`Directory not found: ${targetPath}`);
52
+ }
53
+ // Check if it's a git repository
54
+ if (!(await isGitRepository(targetPath))) {
55
+ return createErrorResult(`Not a git repository: ${targetPath}`);
56
+ }
57
+ try {
58
+ switch (input.action) {
59
+ case 'push':
60
+ return await stashPush(targetPath, input.message, input.includeUntracked ?? false);
61
+ case 'pop':
62
+ return await stashPop(targetPath, input.index ?? 0);
63
+ case 'apply':
64
+ return await stashApply(targetPath, input.index ?? 0);
65
+ case 'list':
66
+ return await stashList(targetPath);
67
+ case 'drop':
68
+ return await stashDrop(targetPath, input.index ?? 0);
69
+ case 'clear':
70
+ return await stashClear(targetPath);
71
+ case 'show':
72
+ return await stashShow(targetPath, input.index ?? 0);
73
+ default:
74
+ return createErrorResult(`Unknown action: ${String(input.action)}`);
75
+ }
76
+ }
77
+ catch (error) {
78
+ return createErrorResult(error instanceof Error ? error.message : String(error));
79
+ }
80
+ }
81
+ /**
82
+ * Push changes to stash
83
+ */
84
+ async function stashPush(repoPath, message, includeUntracked = false) {
85
+ const args = ['stash', 'push'];
86
+ if (message) {
87
+ args.push('-m', message);
88
+ }
89
+ if (includeUntracked) {
90
+ args.push('-u');
91
+ }
92
+ const result = await runGitCommand(args, { cwd: repoPath });
93
+ if (!result.success) {
94
+ return createErrorResult(`Failed to stash changes: ${result.stderr}`);
95
+ }
96
+ // Check if anything was stashed
97
+ if (result.stdout.includes('No local changes to save')) {
98
+ return createErrorResult('No local changes to stash');
99
+ }
100
+ const stashResult = {
101
+ message: message ? `Stashed changes: ${message}` : 'Stashed changes',
102
+ };
103
+ return createSuccessResult(stashResult);
104
+ }
105
+ /**
106
+ * Pop stash (apply and remove)
107
+ */
108
+ async function stashPop(repoPath, index) {
109
+ const stashRef = `stash@{${String(index)}}`;
110
+ const result = await runGitCommand(['stash', 'pop', stashRef], { cwd: repoPath });
111
+ if (!result.success) {
112
+ if (result.stderr.includes('No stash entries found')) {
113
+ return createErrorResult('No stash entries found');
114
+ }
115
+ if (result.stderr.includes('does not exist')) {
116
+ return createErrorResult(`Stash ${stashRef} does not exist`);
117
+ }
118
+ return createErrorResult(`Failed to pop stash: ${result.stderr}`);
119
+ }
120
+ const stashResult = {
121
+ message: `Applied and removed ${stashRef}`,
122
+ };
123
+ return createSuccessResult(stashResult);
124
+ }
125
+ /**
126
+ * Apply stash without removing
127
+ */
128
+ async function stashApply(repoPath, index) {
129
+ const stashRef = `stash@{${String(index)}}`;
130
+ const result = await runGitCommand(['stash', 'apply', stashRef], { cwd: repoPath });
131
+ if (!result.success) {
132
+ if (result.stderr.includes('No stash entries found')) {
133
+ return createErrorResult('No stash entries found');
134
+ }
135
+ if (result.stderr.includes('does not exist')) {
136
+ return createErrorResult(`Stash ${stashRef} does not exist`);
137
+ }
138
+ return createErrorResult(`Failed to apply stash: ${result.stderr}`);
139
+ }
140
+ const stashResult = {
141
+ message: `Applied ${stashRef} (stash still exists)`,
142
+ };
143
+ return createSuccessResult(stashResult);
144
+ }
145
+ /**
146
+ * List all stashes
147
+ */
148
+ async function stashList(repoPath) {
149
+ const result = await runGitCommand(['stash', 'list'], { cwd: repoPath });
150
+ if (!result.success) {
151
+ return createErrorResult(`Failed to list stashes: ${result.stderr}`);
152
+ }
153
+ const stashes = [];
154
+ if (result.stdout) {
155
+ // Parse stash list output
156
+ // Format: stash@{0}: On branch: message
157
+ const lines = result.stdout.split('\n').filter(Boolean);
158
+ for (const line of lines) {
159
+ const match = line.match(/^(stash@\{(\d+)\}): (?:On|WIP on) ([^:]+): (.+)$/);
160
+ if (match) {
161
+ stashes.push({
162
+ ref: match[1],
163
+ index: parseInt(match[2], 10),
164
+ branch: match[3],
165
+ message: match[4],
166
+ });
167
+ }
168
+ else {
169
+ // Fallback for different formats
170
+ const simpleMatch = line.match(/^(stash@\{(\d+)\}): (.+)$/);
171
+ if (simpleMatch) {
172
+ stashes.push({
173
+ ref: simpleMatch[1],
174
+ index: parseInt(simpleMatch[2], 10),
175
+ branch: 'unknown',
176
+ message: simpleMatch[3],
177
+ });
178
+ }
179
+ }
180
+ }
181
+ }
182
+ const stashResult = {
183
+ stashes,
184
+ message: `Found ${String(stashes.length)} stash(es)`,
185
+ };
186
+ return createSuccessResult(stashResult);
187
+ }
188
+ /**
189
+ * Drop a stash
190
+ */
191
+ async function stashDrop(repoPath, index) {
192
+ const stashRef = `stash@{${String(index)}}`;
193
+ const result = await runGitCommand(['stash', 'drop', stashRef], { cwd: repoPath });
194
+ if (!result.success) {
195
+ if (result.stderr.includes('No stash entries found')) {
196
+ return createErrorResult('No stash entries found');
197
+ }
198
+ if (result.stderr.includes('does not exist')) {
199
+ return createErrorResult(`Stash ${stashRef} does not exist`);
200
+ }
201
+ return createErrorResult(`Failed to drop stash: ${result.stderr}`);
202
+ }
203
+ const stashResult = {
204
+ message: `Dropped ${stashRef}`,
205
+ };
206
+ return createSuccessResult(stashResult);
207
+ }
208
+ /**
209
+ * Clear all stashes
210
+ */
211
+ async function stashClear(repoPath) {
212
+ // First check if there are any stashes
213
+ const listResult = await runGitCommand(['stash', 'list'], { cwd: repoPath });
214
+ if (!listResult.stdout) {
215
+ return createErrorResult('No stash entries to clear');
216
+ }
217
+ const result = await runGitCommand(['stash', 'clear'], { cwd: repoPath });
218
+ if (!result.success) {
219
+ return createErrorResult(`Failed to clear stashes: ${result.stderr}`);
220
+ }
221
+ const stashResult = {
222
+ message: 'Cleared all stashes',
223
+ };
224
+ return createSuccessResult(stashResult);
225
+ }
226
+ /**
227
+ * Show stash contents
228
+ */
229
+ async function stashShow(repoPath, index) {
230
+ const stashRef = `stash@{${String(index)}}`;
231
+ // Get stat summary
232
+ const statResult = await runGitCommand(['stash', 'show', stashRef], { cwd: repoPath });
233
+ if (!statResult.success) {
234
+ if (statResult.stderr.includes('No stash entries found')) {
235
+ return createErrorResult('No stash entries found');
236
+ }
237
+ if (statResult.stderr.includes('does not exist')) {
238
+ return createErrorResult(`Stash ${stashRef} does not exist`);
239
+ }
240
+ return createErrorResult(`Failed to show stash: ${statResult.stderr}`);
241
+ }
242
+ // Get diff
243
+ const diffResult = await runGitCommand(['stash', 'show', '-p', stashRef], { cwd: repoPath });
244
+ const stashResult = {
245
+ diff: diffResult.success ? diffResult.stdout : undefined,
246
+ message: statResult.stdout,
247
+ };
248
+ return createSuccessResult(stashResult);
249
+ }
250
+ /**
251
+ * Factory function to create git stash tool with custom options
252
+ */
253
+ export function createGitStashTool(options) {
254
+ return defineTool({
255
+ name: 'git_stash',
256
+ description: 'Manage git stashes. Actions: push, pop, apply, list, drop, clear, show.',
257
+ inputSchema: {
258
+ type: 'object',
259
+ properties: {
260
+ path: {
261
+ type: 'string',
262
+ description: 'Working directory path (default: current directory)',
263
+ },
264
+ action: {
265
+ type: 'string',
266
+ enum: ['push', 'pop', 'apply', 'list', 'drop', 'clear', 'show'],
267
+ description: 'Action to perform',
268
+ },
269
+ message: {
270
+ type: 'string',
271
+ description: 'Stash message (for push)',
272
+ },
273
+ includeUntracked: {
274
+ type: 'boolean',
275
+ description: 'Include untracked files (for push)',
276
+ },
277
+ index: {
278
+ type: 'number',
279
+ description: 'Stash index (default: 0)',
280
+ },
281
+ },
282
+ required: ['action'],
283
+ },
284
+ execute: async (input) => {
285
+ let targetPath = input.path ?? '.';
286
+ // Resolve relative paths
287
+ if (options?.baseDir && !targetPath.startsWith('/')) {
288
+ const nodePath = await import('node:path');
289
+ targetPath = nodePath.join(options.baseDir, targetPath);
290
+ }
291
+ return executeGitStash({ ...input, path: targetPath });
292
+ },
293
+ });
294
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Git Status Tool
3
+ * Shows the working tree status with structured output
4
+ */
5
+ import type { Tool } from '@compilr-dev/agents';
6
+ import type { GitStatusInput } from './types.js';
7
+ /**
8
+ * Git status tool
9
+ */
10
+ export declare const gitStatusTool: Tool<GitStatusInput>;
11
+ /**
12
+ * Factory function to create git status tool with custom options
13
+ */
14
+ export declare function createGitStatusTool(options?: {
15
+ /** Base directory for relative paths */
16
+ baseDir?: string;
17
+ /** Default include untracked setting */
18
+ defaultIncludeUntracked?: boolean;
19
+ }): Tool<GitStatusInput>;
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Git Status Tool
3
+ * Shows the working tree status with structured output
4
+ */
5
+ import { defineTool, createSuccessResult, createErrorResult } from '@compilr-dev/agents';
6
+ import { runGitCommand, isGitRepository, isDirectory, parsePorcelainStatus, parseBranchInfo, xyToStatusType, } from './utils.js';
7
+ /**
8
+ * Git status tool
9
+ */
10
+ export const gitStatusTool = defineTool({
11
+ name: 'git_status',
12
+ description: 'Get the current git working tree status. ' +
13
+ 'Returns branch name, tracking info, staged changes, unstaged changes, and untracked files. ' +
14
+ 'Use to understand what changes exist before committing.',
15
+ inputSchema: {
16
+ type: 'object',
17
+ properties: {
18
+ path: {
19
+ type: 'string',
20
+ description: 'Working directory path (default: current directory)',
21
+ },
22
+ includeUntracked: {
23
+ type: 'boolean',
24
+ description: 'Include untracked files (default: true)',
25
+ },
26
+ short: {
27
+ type: 'boolean',
28
+ description: 'Return short format status string as well (default: false)',
29
+ },
30
+ },
31
+ required: [],
32
+ },
33
+ execute: executeGitStatus,
34
+ });
35
+ /**
36
+ * Execute git status
37
+ */
38
+ async function executeGitStatus(input) {
39
+ const targetPath = input.path ?? process.cwd();
40
+ const includeUntracked = input.includeUntracked ?? true;
41
+ const short = input.short ?? false;
42
+ // Check if path exists
43
+ if (!(await isDirectory(targetPath))) {
44
+ return createErrorResult(`Directory not found: ${targetPath}`);
45
+ }
46
+ // Check if it's a git repository
47
+ if (!(await isGitRepository(targetPath))) {
48
+ return createErrorResult(`Not a git repository: ${targetPath}`);
49
+ }
50
+ try {
51
+ // Run git status with porcelain v2 format for structured output
52
+ const args = ['status', '--porcelain=v2', '--branch'];
53
+ if (includeUntracked) {
54
+ args.push('-uall');
55
+ }
56
+ else {
57
+ args.push('-uno');
58
+ }
59
+ const result = await runGitCommand(args, { cwd: targetPath });
60
+ if (!result.success) {
61
+ return createErrorResult(`git status failed: ${result.stderr}`);
62
+ }
63
+ // Parse branch info
64
+ const branchInfo = parseBranchInfo(result.stdout);
65
+ // Parse file entries
66
+ const entries = parsePorcelainStatus(result.stdout);
67
+ // Categorize entries
68
+ const staged = [];
69
+ const modified = [];
70
+ const untracked = [];
71
+ for (const entry of entries) {
72
+ if (entry.type === 'untracked') {
73
+ untracked.push(entry.path);
74
+ }
75
+ else if (entry.staged && entry.xy[0] !== '.') {
76
+ // Staged changes (first char of XY)
77
+ staged.push({
78
+ path: entry.path,
79
+ status: xyToStatusType(entry.xy, true),
80
+ oldPath: entry.oldPath,
81
+ });
82
+ }
83
+ // Unstaged changes (second char of XY)
84
+ if (entry.xy[1] !== '.' && entry.xy[1] !== '?') {
85
+ modified.push({
86
+ path: entry.path,
87
+ status: xyToStatusType(entry.xy, false),
88
+ });
89
+ }
90
+ }
91
+ // Get short status if requested
92
+ let shortStatus;
93
+ if (short) {
94
+ const shortResult = await runGitCommand(['status', '-sb'], { cwd: targetPath });
95
+ if (shortResult.success) {
96
+ shortStatus = shortResult.stdout;
97
+ }
98
+ }
99
+ const statusResult = {
100
+ branch: branchInfo.branch,
101
+ tracking: branchInfo.upstream
102
+ ? {
103
+ remote: branchInfo.upstream,
104
+ ahead: branchInfo.ahead,
105
+ behind: branchInfo.behind,
106
+ }
107
+ : undefined,
108
+ staged,
109
+ modified,
110
+ untracked,
111
+ isClean: staged.length === 0 && modified.length === 0 && untracked.length === 0,
112
+ shortStatus,
113
+ };
114
+ return createSuccessResult(statusResult);
115
+ }
116
+ catch (error) {
117
+ return createErrorResult(error instanceof Error ? error.message : String(error));
118
+ }
119
+ }
120
+ /**
121
+ * Factory function to create git status tool with custom options
122
+ */
123
+ export function createGitStatusTool(options) {
124
+ return defineTool({
125
+ name: 'git_status',
126
+ description: 'Get the current git working tree status. ' +
127
+ 'Returns branch name, tracking info, staged changes, unstaged changes, and untracked files.',
128
+ inputSchema: {
129
+ type: 'object',
130
+ properties: {
131
+ path: {
132
+ type: 'string',
133
+ description: 'Working directory path (default: current directory)',
134
+ },
135
+ includeUntracked: {
136
+ type: 'boolean',
137
+ description: `Include untracked files (default: ${String(options?.defaultIncludeUntracked ?? true)})`,
138
+ },
139
+ short: {
140
+ type: 'boolean',
141
+ description: 'Return short format status string as well (default: false)',
142
+ },
143
+ },
144
+ required: [],
145
+ },
146
+ execute: async (input) => {
147
+ let targetPath = input.path ?? '.';
148
+ // Resolve relative paths
149
+ if (options?.baseDir && !targetPath.startsWith('/')) {
150
+ const nodePath = await import('node:path');
151
+ targetPath = nodePath.join(options.baseDir, targetPath);
152
+ }
153
+ return executeGitStatus({
154
+ ...input,
155
+ path: targetPath,
156
+ includeUntracked: input.includeUntracked ?? options?.defaultIncludeUntracked ?? true,
157
+ });
158
+ },
159
+ });
160
+ }