@sunilp-org/jam-cli 0.1.0

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 (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +625 -0
  3. package/dist/commands/ask.d.ts +9 -0
  4. package/dist/commands/ask.d.ts.map +1 -0
  5. package/dist/commands/ask.js +84 -0
  6. package/dist/commands/ask.js.map +1 -0
  7. package/dist/commands/auth.d.ts +4 -0
  8. package/dist/commands/auth.d.ts.map +1 -0
  9. package/dist/commands/auth.js +44 -0
  10. package/dist/commands/auth.js.map +1 -0
  11. package/dist/commands/chat.d.ts +10 -0
  12. package/dist/commands/chat.d.ts.map +1 -0
  13. package/dist/commands/chat.js +57 -0
  14. package/dist/commands/chat.js.map +1 -0
  15. package/dist/commands/completion.d.ts +4 -0
  16. package/dist/commands/completion.d.ts.map +1 -0
  17. package/dist/commands/completion.js +156 -0
  18. package/dist/commands/completion.js.map +1 -0
  19. package/dist/commands/config.d.ts +6 -0
  20. package/dist/commands/config.d.ts.map +1 -0
  21. package/dist/commands/config.js +59 -0
  22. package/dist/commands/config.js.map +1 -0
  23. package/dist/commands/diff.d.ts +9 -0
  24. package/dist/commands/diff.d.ts.map +1 -0
  25. package/dist/commands/diff.js +69 -0
  26. package/dist/commands/diff.js.map +1 -0
  27. package/dist/commands/doctor.d.ts +3 -0
  28. package/dist/commands/doctor.d.ts.map +1 -0
  29. package/dist/commands/doctor.js +86 -0
  30. package/dist/commands/doctor.js.map +1 -0
  31. package/dist/commands/explain.d.ts +7 -0
  32. package/dist/commands/explain.d.ts.map +1 -0
  33. package/dist/commands/explain.js +72 -0
  34. package/dist/commands/explain.js.map +1 -0
  35. package/dist/commands/history.d.ts +3 -0
  36. package/dist/commands/history.d.ts.map +1 -0
  37. package/dist/commands/history.js +99 -0
  38. package/dist/commands/history.js.map +1 -0
  39. package/dist/commands/models.d.ts +3 -0
  40. package/dist/commands/models.d.ts.map +1 -0
  41. package/dist/commands/models.js +39 -0
  42. package/dist/commands/models.js.map +1 -0
  43. package/dist/commands/patch.d.ts +8 -0
  44. package/dist/commands/patch.d.ts.map +1 -0
  45. package/dist/commands/patch.js +158 -0
  46. package/dist/commands/patch.js.map +1 -0
  47. package/dist/commands/run.d.ts +6 -0
  48. package/dist/commands/run.d.ts.map +1 -0
  49. package/dist/commands/run.js +241 -0
  50. package/dist/commands/run.js.map +1 -0
  51. package/dist/commands/search.d.ts +9 -0
  52. package/dist/commands/search.d.ts.map +1 -0
  53. package/dist/commands/search.js +128 -0
  54. package/dist/commands/search.js.map +1 -0
  55. package/dist/config/defaults.d.ts +3 -0
  56. package/dist/config/defaults.d.ts.map +1 -0
  57. package/dist/config/defaults.js +16 -0
  58. package/dist/config/defaults.js.map +1 -0
  59. package/dist/config/loader.d.ts +4 -0
  60. package/dist/config/loader.d.ts.map +1 -0
  61. package/dist/config/loader.js +103 -0
  62. package/dist/config/loader.js.map +1 -0
  63. package/dist/config/schema.d.ts +104 -0
  64. package/dist/config/schema.d.ts.map +1 -0
  65. package/dist/config/schema.js +21 -0
  66. package/dist/config/schema.js.map +1 -0
  67. package/dist/index.d.ts +3 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +249 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/providers/base.d.ts +32 -0
  72. package/dist/providers/base.d.ts.map +1 -0
  73. package/dist/providers/base.js +2 -0
  74. package/dist/providers/base.js.map +1 -0
  75. package/dist/providers/factory.d.ts +4 -0
  76. package/dist/providers/factory.d.ts.map +1 -0
  77. package/dist/providers/factory.js +13 -0
  78. package/dist/providers/factory.js.map +1 -0
  79. package/dist/providers/ollama.d.ts +14 -0
  80. package/dist/providers/ollama.d.ts.map +1 -0
  81. package/dist/providers/ollama.js +152 -0
  82. package/dist/providers/ollama.js.map +1 -0
  83. package/dist/storage/history.d.ts +21 -0
  84. package/dist/storage/history.d.ts.map +1 -0
  85. package/dist/storage/history.js +103 -0
  86. package/dist/storage/history.js.map +1 -0
  87. package/dist/tools/apply_patch.d.ts +3 -0
  88. package/dist/tools/apply_patch.d.ts.map +1 -0
  89. package/dist/tools/apply_patch.js +86 -0
  90. package/dist/tools/apply_patch.js.map +1 -0
  91. package/dist/tools/git_diff.d.ts +3 -0
  92. package/dist/tools/git_diff.d.ts.map +1 -0
  93. package/dist/tools/git_diff.js +49 -0
  94. package/dist/tools/git_diff.js.map +1 -0
  95. package/dist/tools/git_status.d.ts +3 -0
  96. package/dist/tools/git_status.d.ts.map +1 -0
  97. package/dist/tools/git_status.js +26 -0
  98. package/dist/tools/git_status.js.map +1 -0
  99. package/dist/tools/index.d.ts +10 -0
  100. package/dist/tools/index.d.ts.map +1 -0
  101. package/dist/tools/index.js +10 -0
  102. package/dist/tools/index.js.map +1 -0
  103. package/dist/tools/list_dir.d.ts +3 -0
  104. package/dist/tools/list_dir.d.ts.map +1 -0
  105. package/dist/tools/list_dir.js +61 -0
  106. package/dist/tools/list_dir.js.map +1 -0
  107. package/dist/tools/read_file.d.ts +3 -0
  108. package/dist/tools/read_file.d.ts.map +1 -0
  109. package/dist/tools/read_file.js +83 -0
  110. package/dist/tools/read_file.js.map +1 -0
  111. package/dist/tools/registry.d.ts +12 -0
  112. package/dist/tools/registry.d.ts.map +1 -0
  113. package/dist/tools/registry.js +76 -0
  114. package/dist/tools/registry.js.map +1 -0
  115. package/dist/tools/run_command.d.ts +6 -0
  116. package/dist/tools/run_command.d.ts.map +1 -0
  117. package/dist/tools/run_command.js +37 -0
  118. package/dist/tools/run_command.js.map +1 -0
  119. package/dist/tools/search_text.d.ts +3 -0
  120. package/dist/tools/search_text.d.ts.map +1 -0
  121. package/dist/tools/search_text.js +171 -0
  122. package/dist/tools/search_text.js.map +1 -0
  123. package/dist/tools/types.d.ts +25 -0
  124. package/dist/tools/types.d.ts.map +1 -0
  125. package/dist/tools/types.js +2 -0
  126. package/dist/tools/types.js.map +1 -0
  127. package/dist/tools/write_file.d.ts +3 -0
  128. package/dist/tools/write_file.d.ts.map +1 -0
  129. package/dist/tools/write_file.js +61 -0
  130. package/dist/tools/write_file.js.map +1 -0
  131. package/dist/ui/chat.d.ts +10 -0
  132. package/dist/ui/chat.d.ts.map +1 -0
  133. package/dist/ui/chat.js +173 -0
  134. package/dist/ui/chat.js.map +1 -0
  135. package/dist/ui/logo.d.ts +14 -0
  136. package/dist/ui/logo.d.ts.map +1 -0
  137. package/dist/ui/logo.js +76 -0
  138. package/dist/ui/logo.js.map +1 -0
  139. package/dist/ui/renderer.d.ts +15 -0
  140. package/dist/ui/renderer.d.ts.map +1 -0
  141. package/dist/ui/renderer.js +61 -0
  142. package/dist/ui/renderer.js.map +1 -0
  143. package/dist/utils/errors.d.ts +14 -0
  144. package/dist/utils/errors.d.ts.map +1 -0
  145. package/dist/utils/errors.js +26 -0
  146. package/dist/utils/errors.js.map +1 -0
  147. package/dist/utils/logger.d.ts +17 -0
  148. package/dist/utils/logger.d.ts.map +1 -0
  149. package/dist/utils/logger.js +50 -0
  150. package/dist/utils/logger.js.map +1 -0
  151. package/dist/utils/secrets.d.ts +4 -0
  152. package/dist/utils/secrets.d.ts.map +1 -0
  153. package/dist/utils/secrets.js +39 -0
  154. package/dist/utils/secrets.js.map +1 -0
  155. package/dist/utils/stream.d.ts +12 -0
  156. package/dist/utils/stream.d.ts.map +1 -0
  157. package/dist/utils/stream.js +54 -0
  158. package/dist/utils/stream.js.map +1 -0
  159. package/dist/utils/workspace.d.ts +14 -0
  160. package/dist/utils/workspace.d.ts.map +1 -0
  161. package/dist/utils/workspace.js +39 -0
  162. package/dist/utils/workspace.js.map +1 -0
  163. package/package.json +84 -0
@@ -0,0 +1,241 @@
1
+ import { createInterface } from 'node:readline/promises';
2
+ import { loadConfig, getActiveProfile } from '../config/loader.js';
3
+ import { printError, printWarning } from '../ui/renderer.js';
4
+ import { JamError } from '../utils/errors.js';
5
+ import { getWorkspaceRoot } from '../utils/workspace.js';
6
+ // Inline tool definitions for the run command (mirrors src/tools/ implementations)
7
+ const TOOL_SCHEMAS = [
8
+ {
9
+ type: 'function',
10
+ function: {
11
+ name: 'read_file',
12
+ description: 'Read the contents of a file',
13
+ parameters: {
14
+ type: 'object',
15
+ properties: {
16
+ path: { type: 'string', description: 'File path relative to workspace root' },
17
+ start_line: { type: 'number', description: 'Start line (optional)' },
18
+ end_line: { type: 'number', description: 'End line (optional)' },
19
+ },
20
+ required: ['path'],
21
+ },
22
+ },
23
+ },
24
+ {
25
+ type: 'function',
26
+ function: {
27
+ name: 'list_dir',
28
+ description: 'List files and directories in a path',
29
+ parameters: {
30
+ type: 'object',
31
+ properties: { path: { type: 'string', description: 'Directory path (default: ".")' } },
32
+ required: [],
33
+ },
34
+ },
35
+ },
36
+ {
37
+ type: 'function',
38
+ function: {
39
+ name: 'search_text',
40
+ description: 'Search for text in the codebase using ripgrep',
41
+ parameters: {
42
+ type: 'object',
43
+ properties: {
44
+ query: { type: 'string', description: 'Search query (regex supported)' },
45
+ glob: { type: 'string', description: 'File glob pattern (e.g. "*.ts")' },
46
+ max_results: { type: 'number', description: 'Max results (default 20)' },
47
+ },
48
+ required: ['query'],
49
+ },
50
+ },
51
+ },
52
+ {
53
+ type: 'function',
54
+ function: {
55
+ name: 'git_status',
56
+ description: 'Get current git status',
57
+ parameters: { type: 'object', properties: {}, required: [] },
58
+ },
59
+ },
60
+ {
61
+ type: 'function',
62
+ function: {
63
+ name: 'git_diff',
64
+ description: 'Get git diff',
65
+ parameters: {
66
+ type: 'object',
67
+ properties: {
68
+ staged: { type: 'boolean', description: 'Show staged changes' },
69
+ path: { type: 'string', description: 'Limit to a specific path' },
70
+ },
71
+ required: [],
72
+ },
73
+ },
74
+ },
75
+ {
76
+ type: 'function',
77
+ function: {
78
+ name: 'write_file',
79
+ description: 'Write content to a file (requires confirmation)',
80
+ parameters: {
81
+ type: 'object',
82
+ properties: {
83
+ path: { type: 'string', description: 'File path' },
84
+ content: { type: 'string', description: 'File content' },
85
+ mode: { type: 'string', description: '"overwrite" or "append" (default: overwrite)' },
86
+ },
87
+ required: ['path', 'content'],
88
+ },
89
+ },
90
+ },
91
+ {
92
+ type: 'function',
93
+ function: {
94
+ name: 'apply_patch',
95
+ description: 'Apply a unified diff patch (requires confirmation)',
96
+ parameters: {
97
+ type: 'object',
98
+ properties: { patch: { type: 'string', description: 'Unified diff content' } },
99
+ required: ['patch'],
100
+ },
101
+ },
102
+ },
103
+ ];
104
+ const READONLY_TOOLS = new Set(['read_file', 'list_dir', 'search_text', 'git_status', 'git_diff']);
105
+ async function confirmToolCall(toolName, args) {
106
+ process.stderr.write(`\n[Tool Request] ${toolName}\n`);
107
+ process.stderr.write(`Arguments: ${JSON.stringify(args, null, 2)}\n`);
108
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
109
+ const answer = await rl.question('Allow this tool call? [y/N] ');
110
+ rl.close();
111
+ return answer.toLowerCase() === 'y';
112
+ }
113
+ async function executeTool(toolName, args, workspaceRoot, policy) {
114
+ const isReadonly = READONLY_TOOLS.has(toolName);
115
+ if (!isReadonly) {
116
+ if (policy === 'never') {
117
+ throw new JamError(`Tool "${toolName}" is a write tool and policy is set to "never"`, 'TOOL_DENIED');
118
+ }
119
+ if (policy === 'ask_every_time') {
120
+ const allowed = await confirmToolCall(toolName, args);
121
+ if (!allowed) {
122
+ throw new JamError(`Tool "${toolName}" was denied by the user`, 'TOOL_DENIED');
123
+ }
124
+ }
125
+ }
126
+ // Lazy import the tool implementation from the tools layer
127
+ const { createDefaultRegistry } = await import('../tools/registry.js');
128
+ const registry = createDefaultRegistry();
129
+ const result = await registry.get(toolName)?.execute(args, { workspaceRoot, cwd: process.cwd() });
130
+ if (!result) {
131
+ throw new JamError(`Unknown tool: ${toolName}`, 'TOOL_NOT_FOUND');
132
+ }
133
+ return result.error ? `Error: ${result.error}` : result.output;
134
+ }
135
+ export async function runRun(instruction, options) {
136
+ if (!instruction) {
137
+ await printError('Provide an instruction. Usage: jam run "<instruction>"');
138
+ process.exit(1);
139
+ }
140
+ try {
141
+ const workspaceRoot = await getWorkspaceRoot();
142
+ const config = await loadConfig(process.cwd(), options);
143
+ const profile = getActiveProfile(config);
144
+ process.stderr.write(`Starting task: ${instruction}\n`);
145
+ process.stderr.write(`Provider: ${profile.provider}, Model: ${profile.model ?? 'default'}\n\n`);
146
+ const messages = [
147
+ {
148
+ role: 'user',
149
+ content: instruction,
150
+ },
151
+ ];
152
+ const systemPrompt = profile.systemPrompt ??
153
+ `You are a developer assistant with access to the local codebase. ` +
154
+ `Use the provided tools to read files, search code, and make changes. ` +
155
+ `Always validate your changes. Workspace root: ${workspaceRoot}`;
156
+ // Agentic loop — up to 10 iterations
157
+ const MAX_ITERATIONS = 10;
158
+ for (let iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
159
+ const baseUrl = profile.baseUrl ?? 'http://localhost:11434';
160
+ const model = profile.model ?? 'llama3.2';
161
+ // Call Ollama with tools
162
+ let response;
163
+ try {
164
+ response = await fetch(`${baseUrl.replace(/\/$/, '')}/api/chat`, {
165
+ method: 'POST',
166
+ headers: { 'Content-Type': 'application/json' },
167
+ body: JSON.stringify({
168
+ model,
169
+ messages: [
170
+ { role: 'system', content: systemPrompt },
171
+ ...messages.map((m) => ({ role: m.role, content: m.content })),
172
+ ],
173
+ tools: TOOL_SCHEMAS,
174
+ stream: false,
175
+ }),
176
+ signal: AbortSignal.timeout(120_000),
177
+ });
178
+ }
179
+ catch (err) {
180
+ throw new JamError('Failed to connect to provider', 'PROVIDER_UNAVAILABLE', {
181
+ cause: err,
182
+ retryable: true,
183
+ });
184
+ }
185
+ if (!response.ok) {
186
+ const text = await response.text().catch(() => '');
187
+ throw new JamError(`Provider error ${response.status}: ${text}`, 'PROVIDER_STREAM_ERROR');
188
+ }
189
+ const data = (await response.json());
190
+ const assistantMsg = data.message;
191
+ // Add assistant message to conversation
192
+ messages.push({
193
+ role: 'assistant',
194
+ content: assistantMsg.content ?? '',
195
+ });
196
+ // Print any text content
197
+ if (assistantMsg.content) {
198
+ process.stdout.write('\n[Assistant]\n' + assistantMsg.content + '\n');
199
+ }
200
+ // Check for tool calls
201
+ const toolCalls = assistantMsg.tool_calls;
202
+ if (!toolCalls || toolCalls.length === 0) {
203
+ // No tool calls — task is done
204
+ break;
205
+ }
206
+ // Execute each tool call
207
+ for (const tc of toolCalls) {
208
+ const toolName = tc.function.name;
209
+ const args = tc.function.arguments;
210
+ process.stderr.write(`\n[Tool] ${toolName}(${JSON.stringify(args)})\n`);
211
+ let toolOutput;
212
+ try {
213
+ toolOutput = await executeTool(toolName, args, workspaceRoot, config.toolPolicy);
214
+ process.stderr.write(`[Result] ${toolOutput.slice(0, 200)}${toolOutput.length > 200 ? '...' : ''}\n`);
215
+ }
216
+ catch (err) {
217
+ const jamErr = JamError.fromUnknown(err);
218
+ if (jamErr.code === 'TOOL_DENIED') {
219
+ toolOutput = `Tool call was denied: ${jamErr.message}`;
220
+ await printWarning(jamErr.message);
221
+ }
222
+ else {
223
+ toolOutput = `Tool execution failed: ${jamErr.message}`;
224
+ }
225
+ }
226
+ // Add tool result to conversation as a user message
227
+ messages.push({
228
+ role: 'user',
229
+ content: `[Tool result for ${toolName}]\n${toolOutput}`,
230
+ });
231
+ }
232
+ }
233
+ process.stderr.write('\nTask complete.\n');
234
+ }
235
+ catch (err) {
236
+ const jamErr = JamError.fromUnknown(err);
237
+ await printError(jamErr.message);
238
+ process.exit(1);
239
+ }
240
+ }
241
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { CliOverrides } from '../config/schema.js';
2
+ export interface SearchOptions extends CliOverrides {
3
+ glob?: string;
4
+ maxResults?: number;
5
+ ask?: boolean;
6
+ json?: boolean;
7
+ }
8
+ export declare function runSearch(query: string | undefined, options: SearchOptions): Promise<void>;
9
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAIxD,MAAM,WAAW,aAAc,SAAQ,YAAY;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAyED,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAyDhG"}
@@ -0,0 +1,128 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ import { readdir, readFile, stat } from 'node:fs/promises';
4
+ import { join, relative } from 'node:path';
5
+ import { loadConfig, getActiveProfile } from '../config/loader.js';
6
+ import { createProvider } from '../providers/factory.js';
7
+ import { withRetry, collectStream } from '../utils/stream.js';
8
+ import { streamToStdout, printJsonResult, printError } from '../ui/renderer.js';
9
+ import { JamError } from '../utils/errors.js';
10
+ import { getWorkspaceRoot } from '../utils/workspace.js';
11
+ const execFileAsync = promisify(execFile);
12
+ async function searchWithRipgrep(query, cwd, glob, maxResults = 20) {
13
+ const args = [
14
+ '--line-number',
15
+ '--color=never',
16
+ '--max-count=1',
17
+ `--max-filesize=500K`,
18
+ '-m', String(maxResults),
19
+ ];
20
+ if (glob)
21
+ args.push('--glob', glob);
22
+ args.push('--', query, '.');
23
+ const { stdout } = await execFileAsync('rg', args, { cwd, maxBuffer: 2 * 1024 * 1024 });
24
+ return stdout.trim();
25
+ }
26
+ async function searchFallback(query, cwd, glob, maxResults = 20) {
27
+ const results = [];
28
+ const queryLower = query.toLowerCase();
29
+ async function walk(dir) {
30
+ if (results.length >= maxResults)
31
+ return;
32
+ let entries;
33
+ try {
34
+ entries = await readdir(dir, { withFileTypes: true });
35
+ }
36
+ catch {
37
+ return;
38
+ }
39
+ for (const entry of entries) {
40
+ if (results.length >= maxResults)
41
+ return;
42
+ const fullPath = join(dir, entry.name);
43
+ if (entry.isDirectory()) {
44
+ if (['node_modules', '.git', 'dist', '.cache'].includes(entry.name))
45
+ continue;
46
+ await walk(fullPath);
47
+ }
48
+ else if (entry.isFile()) {
49
+ if (glob) {
50
+ const { minimatch } = await import('minimatch').catch(() => ({ minimatch: null }));
51
+ if (minimatch && !minimatch(entry.name, glob))
52
+ continue;
53
+ }
54
+ try {
55
+ const s = await stat(fullPath);
56
+ if (s.size > 500_000)
57
+ continue;
58
+ const content = await readFile(fullPath, 'utf-8');
59
+ const lines = content.split('\n');
60
+ lines.forEach((line, i) => {
61
+ if (results.length >= maxResults)
62
+ return;
63
+ if (line.toLowerCase().includes(queryLower)) {
64
+ const rel = relative(cwd, fullPath);
65
+ results.push(`${rel}:${i + 1}: ${line.trim()}`);
66
+ }
67
+ });
68
+ }
69
+ catch {
70
+ // skip unreadable files
71
+ }
72
+ }
73
+ }
74
+ }
75
+ await walk(cwd);
76
+ return results.join('\n');
77
+ }
78
+ export async function runSearch(query, options) {
79
+ if (!query) {
80
+ await printError('Provide a search query. Usage: jam search "<query>"');
81
+ process.exit(1);
82
+ }
83
+ try {
84
+ const workspaceRoot = await getWorkspaceRoot();
85
+ const maxResults = options.maxResults ?? 20;
86
+ let results;
87
+ try {
88
+ results = await searchWithRipgrep(query, workspaceRoot, options.glob, maxResults);
89
+ }
90
+ catch {
91
+ // rg not available or failed — use JS fallback
92
+ results = await searchFallback(query, workspaceRoot, options.glob, maxResults);
93
+ }
94
+ if (!results) {
95
+ process.stdout.write(`No results found for: ${query}\n`);
96
+ return;
97
+ }
98
+ if (!options.ask) {
99
+ process.stdout.write(results + '\n');
100
+ return;
101
+ }
102
+ // Pipe results to AI
103
+ const config = await loadConfig(process.cwd(), options);
104
+ const profile = getActiveProfile(config);
105
+ const adapter = await createProvider(profile);
106
+ const prompt = `I searched the codebase for "${query}" and found these results:\n\n` +
107
+ `\`\`\`\n${results}\n\`\`\`\n\n` +
108
+ `Please explain what these results tell us about the codebase and the query topic.`;
109
+ const request = {
110
+ messages: [{ role: 'user', content: prompt }],
111
+ model: profile.model,
112
+ systemPrompt: profile.systemPrompt,
113
+ };
114
+ if (options.json) {
115
+ const { text, usage } = await collectStream(withRetry(() => adapter.streamCompletion(request)));
116
+ printJsonResult({ response: text, usage, model: profile.model });
117
+ }
118
+ else {
119
+ await streamToStdout(withRetry(() => adapter.streamCompletion(request)));
120
+ }
121
+ }
122
+ catch (err) {
123
+ const jamErr = JamError.fromUnknown(err);
124
+ await printError(jamErr.message);
125
+ process.exit(1);
126
+ }
127
+ }
128
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAS1C,KAAK,UAAU,iBAAiB,CAC9B,KAAa,EACb,GAAW,EACX,IAAa,EACb,UAAU,GAAG,EAAE;IAEf,MAAM,IAAI,GAAG;QACX,eAAe;QACf,eAAe;QACf,eAAe;QACf,qBAAqB;QACrB,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC;KACzB,CAAC;IACF,IAAI,IAAI;QAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACpC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IAE5B,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,CAAC;IACxF,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;AACvB,CAAC;AAED,KAAK,UAAU,cAAc,CAC3B,KAAa,EACb,GAAW,EACX,IAAa,EACb,UAAU,GAAG,EAAE;IAEf,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAEvC,KAAK,UAAU,IAAI,CAAC,GAAW;QAC7B,IAAI,OAAO,CAAC,MAAM,IAAI,UAAU;YAAE,OAAO;QACzC,IAAI,OAAO,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,OAAO,CAAC,MAAM,IAAI,UAAU;gBAAE,OAAO;YACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACvC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;oBAAE,SAAS;gBAC9E,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvB,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC1B,IAAI,IAAI,EAAE,CAAC;oBACT,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;oBACnF,IAAI,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC;wBAAE,SAAS;gBAC1D,CAAC;gBACD,IAAI,CAAC;oBACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;oBAC/B,IAAI,CAAC,CAAC,IAAI,GAAG,OAAO;wBAAE,SAAS;oBAC/B,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;oBAClD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBAClC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;wBACxB,IAAI,OAAO,CAAC,MAAM,IAAI,UAAU;4BAAE,OAAO;wBACzC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;4BAC5C,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;4BACpC,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;wBAClD,CAAC;oBACH,CAAC,CAAC,CAAC;gBACL,CAAC;gBAAC,MAAM,CAAC;oBACP,wBAAwB;gBAC1B,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAyB,EAAE,OAAsB;IAC/E,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,UAAU,CAAC,qDAAqD,CAAC,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,MAAM,gBAAgB,EAAE,CAAC;QAC/C,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;QAE5C,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,iBAAiB,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACpF,CAAC;QAAC,MAAM,CAAC;YACP,+CAA+C;YAC/C,OAAO,GAAG,MAAM,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACjF,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,KAAK,IAAI,CAAC,CAAC;YACzD,OAAO;QACT,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;YACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;YACrC,OAAO;QACT,CAAC;QAED,qBAAqB;QACrB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;QACxD,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;QACzC,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC;QAE9C,MAAM,MAAM,GACV,gCAAgC,KAAK,gCAAgC;YACrE,WAAW,OAAO,cAAc;YAChC,mFAAmF,CAAC;QAEtF,MAAM,OAAO,GAAG;YACd,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;YACtD,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,YAAY,EAAE,OAAO,CAAC,YAAY;SACnC,CAAC;QAEF,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,aAAa,CACzC,SAAS,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CACnD,CAAC;YACF,eAAe,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QACnE,CAAC;aAAM,CAAC;YACN,MAAM,cAAc,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACzC,MAAM,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { JamConfig } from './schema.js';
2
+ export declare const CONFIG_DEFAULTS: JamConfig;
3
+ //# sourceMappingURL=defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,eAAO,MAAM,eAAe,EAAE,SAc7B,CAAC"}
@@ -0,0 +1,16 @@
1
+ export const CONFIG_DEFAULTS = {
2
+ defaultProfile: 'default',
3
+ profiles: {
4
+ default: {
5
+ provider: 'ollama',
6
+ model: 'llama3.2',
7
+ baseUrl: 'http://localhost:11434',
8
+ },
9
+ },
10
+ toolPolicy: 'ask_every_time',
11
+ toolAllowlist: [],
12
+ historyEnabled: true,
13
+ logLevel: 'warn',
14
+ redactPatterns: [],
15
+ };
16
+ //# sourceMappingURL=defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAc;IACxC,cAAc,EAAE,SAAS;IACzB,QAAQ,EAAE;QACR,OAAO,EAAE;YACP,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,UAAU;YACjB,OAAO,EAAE,wBAAwB;SAClC;KACF;IACD,UAAU,EAAE,gBAAgB;IAC5B,aAAa,EAAE,EAAE;IACjB,cAAc,EAAE,IAAI;IACpB,QAAQ,EAAE,MAAM;IAChB,cAAc,EAAE,EAAE;CACnB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { JamConfig, CliOverrides, Profile } from './schema.js';
2
+ export declare function loadConfig(cwd?: string, cliOverrides?: CliOverrides): Promise<JamConfig>;
3
+ export declare function getActiveProfile(config: JamConfig): Profile;
4
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AA8EpE,wBAAsB,UAAU,CAC9B,GAAG,GAAE,MAAsB,EAC3B,YAAY,GAAE,YAAiB,GAC9B,OAAO,CAAC,SAAS,CAAC,CA8BpB;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAS3D"}
@@ -0,0 +1,103 @@
1
+ import { cosmiconfig } from 'cosmiconfig';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { JamConfigSchema } from './schema.js';
5
+ import { CONFIG_DEFAULTS } from './defaults.js';
6
+ import { JamError } from '../utils/errors.js';
7
+ const MODULE_NAME = 'jam';
8
+ function deepMergeProfiles(base, override) {
9
+ const result = { ...base };
10
+ for (const [key, val] of Object.entries(override)) {
11
+ const existing = result[key];
12
+ if (existing) {
13
+ result[key] = { ...existing, ...val };
14
+ }
15
+ else {
16
+ result[key] = val;
17
+ }
18
+ }
19
+ return result;
20
+ }
21
+ function mergeConfigs(base, override) {
22
+ return {
23
+ ...base,
24
+ ...override,
25
+ profiles: deepMergeProfiles(base.profiles, override.profiles ?? {}),
26
+ toolAllowlist: override.toolAllowlist ?? base.toolAllowlist,
27
+ redactPatterns: override.redactPatterns ?? base.redactPatterns,
28
+ };
29
+ }
30
+ async function loadFile(searchFrom) {
31
+ const explorer = cosmiconfig(MODULE_NAME, {
32
+ searchPlaces: [
33
+ `.${MODULE_NAME}rc`,
34
+ `.${MODULE_NAME}rc.json`,
35
+ `.${MODULE_NAME}rc.yaml`,
36
+ `.${MODULE_NAME}rc.yml`,
37
+ `.${MODULE_NAME}/config.json`,
38
+ `${MODULE_NAME}.config.js`,
39
+ `${MODULE_NAME}.config.cjs`,
40
+ ],
41
+ stopDir: searchFrom,
42
+ });
43
+ const result = await explorer.search(searchFrom);
44
+ if (!result)
45
+ return {};
46
+ const parsed = JamConfigSchema.partial().safeParse(result.config);
47
+ if (!parsed.success) {
48
+ throw new JamError(`Invalid config at ${result.filepath}: ${parsed.error.message}`, 'CONFIG_INVALID');
49
+ }
50
+ return parsed.data;
51
+ }
52
+ async function loadUserConfig() {
53
+ const userConfigDir = join(homedir(), '.config', MODULE_NAME);
54
+ const explorer = cosmiconfig(MODULE_NAME, {
55
+ searchPlaces: ['config.json', 'config.yaml', 'config.yml'],
56
+ stopDir: userConfigDir,
57
+ });
58
+ const result = await explorer.search(userConfigDir);
59
+ if (!result)
60
+ return {};
61
+ const parsed = JamConfigSchema.partial().safeParse(result.config);
62
+ if (!parsed.success) {
63
+ throw new JamError(`Invalid user config at ${result.filepath}: ${parsed.error.message}`, 'CONFIG_INVALID');
64
+ }
65
+ return parsed.data;
66
+ }
67
+ export async function loadConfig(cwd = process.cwd(), cliOverrides = {}) {
68
+ const userConfig = await loadUserConfig();
69
+ const repoConfig = await loadFile(cwd);
70
+ let config = mergeConfigs(CONFIG_DEFAULTS, userConfig);
71
+ config = mergeConfigs(config, repoConfig);
72
+ // Apply CLI overrides to the active profile
73
+ const profileName = cliOverrides.profile ?? config.defaultProfile;
74
+ if (cliOverrides.provider || cliOverrides.model || cliOverrides.baseUrl) {
75
+ const existingProfile = config.profiles[profileName] ?? { provider: 'ollama' };
76
+ const overriddenProfile = {
77
+ ...existingProfile,
78
+ provider: cliOverrides.provider ?? existingProfile.provider,
79
+ ...(cliOverrides.model ? { model: cliOverrides.model } : {}),
80
+ ...(cliOverrides.baseUrl ? { baseUrl: cliOverrides.baseUrl } : {}),
81
+ };
82
+ config = {
83
+ ...config,
84
+ defaultProfile: profileName,
85
+ profiles: {
86
+ ...config.profiles,
87
+ [profileName]: overriddenProfile,
88
+ },
89
+ };
90
+ }
91
+ else if (cliOverrides.profile) {
92
+ config = { ...config, defaultProfile: profileName };
93
+ }
94
+ return config;
95
+ }
96
+ export function getActiveProfile(config) {
97
+ const profile = config.profiles[config.defaultProfile];
98
+ if (!profile) {
99
+ throw new JamError(`Profile "${config.defaultProfile}" not found in config`, 'CONFIG_NOT_FOUND');
100
+ }
101
+ return profile;
102
+ }
103
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}