@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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026-present Sunil Prakash. All rights reserved.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,625 @@
1
+ <div align="center">
2
+
3
+ ```
4
+ ╭───────────────────────────────────╮
5
+ │ │
6
+ │ ██╗ █████╗ ███╗ ███╗ │
7
+ │ ██║ ██╔══██╗ ████╗ ████║ │
8
+ │ ██║ ███████║ ██╔████╔██║ │
9
+ │ ██ ██║ ██╔══██║ ██║╚██╔╝██║ │
10
+ │ ╚████╔╝ ██║ ██║ ██║ ╚═╝ ██║ │
11
+ │ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ │
12
+ │ │
13
+ │ developer-first AI CLI │
14
+ │ │
15
+ ╰───────────────────────────────────╯
16
+ ```
17
+
18
+ # Jam CLI
19
+
20
+ **The developer-first AI assistant for the terminal.**
21
+
22
+ [![CI](https://github.com/sunilp/jam-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/sunilp/jam-cli/actions/workflows/ci.yml)
23
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
24
+ [![Node.js 20+](https://img.shields.io/badge/Node.js-20%2B-green.svg)](https://nodejs.org)
25
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)
26
+ [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org)
27
+
28
+ Ask questions • Explain code • Review diffs • Generate patches • Run agentic tasks
29
+
30
+ *All from your command line, powered by any Ollama-hosted model.*
31
+
32
+ [Getting Started](#quick-start) · [Commands](#commands) · [Configuration](#configuration) · [Contributing](#contributing) · [Security](#security-policy)
33
+
34
+ </div>
35
+
36
+ ---
37
+
38
+ ## Why Jam?
39
+
40
+ Most AI coding tools are built around a single vendor's model, require a browser or IDE plugin, and send your code to a remote server you don't control.
41
+
42
+ **Jam is different by design:**
43
+
44
+ - It runs **entirely on your machine** by default — your code never leaves your filesystem
45
+ - It is **not tied to any single model or provider** — you choose the engine; Jam is the harness
46
+ - It behaves like a proper **Unix tool** — pipeable, composable, and scriptable
47
+ - It treats **code modification as a transaction** — validate first, preview always, confirm before applying
48
+ - It is **built to be contributed to** — clean TypeScript, well-tested, architecture documented below
49
+
50
+ ---
51
+
52
+ ## Highlights
53
+
54
+ | | Feature | Description |
55
+ |---|---------|-------------|
56
+ | ⚡ | **Streaming output** | Responses begin rendering on the first token |
57
+ | 💬 | **Interactive chat** | Multi-turn sessions with history and resume |
58
+ | 📂 | **Repo-aware** | Explain files, search code, review diffs with full workspace context |
59
+ | 🩹 | **Patch workflow** | Generate unified diffs, validate, preview, and apply with confirmation |
60
+ | 🤖 | **Tool-calling agent** | `jam run` gives the model access to local tools (read, search, diff, apply) |
61
+ | 🔌 | **Pluggable providers** | Ollama by default; adapter pattern for adding any LLM |
62
+ | ⚙️ | **Layered config** | Global → repo → CLI flags; multiple named profiles |
63
+ | 🔐 | **Secure secrets** | OS keychain via keytar, env var fallback |
64
+ | 🐚 | **Shell completions** | Bash and Zsh |
65
+ | 🏠 | **Privacy-first** | Runs locally — your code never leaves your machine |
66
+
67
+ ---
68
+
69
+ ## Design Philosophy
70
+
71
+ > The best developer tools disappear into your workflow. They don't ask you to change how you work — they work the way you already do.
72
+
73
+ **You own the model.** Jam's `ProviderAdapter` is a clean interface — swap the AI engine with a config change, not a rewrite. No vendor lock-in, no model loyalty.
74
+
75
+ **Your code stays private.** The default is `localhost`. Nothing leaves your machine unless you explicitly point Jam at a remote provider. This isn't just a feature — it's the architecture.
76
+
77
+ **Changes are transactions, not actions.** `jam patch` validates with `git apply --check` before anything is touched, shows a full preview, and waits for explicit confirmation. No "undo" needed — changes never happen without your approval.
78
+
79
+ **Unix composability.** `jam ask` reads stdin, writes stdout, supports `--json`. It's a pipe stage, not a walled garden.
80
+
81
+ **Security is configuration, not hope.** Tool permissions (`toolPolicy`), allowed operations (`toolAllowlist`), and log redaction (`redactPatterns`) are declarative config — committable to `.jamrc` so your whole team inherits the same guardrails.
82
+
83
+ ---
84
+
85
+ ## Who Is Jam For?
86
+
87
+ | Situation | Why Jam fits |
88
+ |-----------|-------------|
89
+ | You work in a **security-sensitive codebase** | Local-only by default — nothing leaves your machine |
90
+ | You want to **use different models** for different tasks | Named profiles + provider adapter — switch with `--profile` |
91
+ | You live in the **terminal** and resent leaving it | Every command is designed for the shell, not a browser tab |
92
+ | You're on a **corporate network** that blocks AI services | Point `baseUrl` at an internal Ollama instance and you're done |
93
+ | You want an AI tool that fits into **CI/CD scripts** | `--json` output, stdin support, non-zero exit codes on errors |
94
+ | You want to **contribute to an AI tool** without fighting vendor APIs | The hard parts (streaming, tool-calling, config) are already built cleanly |
95
+
96
+ ---
97
+
98
+ ## Quick Start
99
+
100
+ ### Prerequisites
101
+
102
+ - **Node.js 20+**
103
+ - **[Ollama](https://ollama.ai)** running locally (`ollama serve`)
104
+ - A pulled model: `ollama pull llama3.2`
105
+
106
+ ### Install
107
+
108
+ ```bash
109
+ # Global install (once published to npm)
110
+ npm install -g jam-cli
111
+
112
+ # Or run from source
113
+ git clone https://github.com/sunilp/jam-cli.git
114
+ cd jam-cli
115
+ npm install
116
+ npm run build
117
+ npm link # makes `jam` available globally
118
+ ```
119
+
120
+ ### Verify
121
+
122
+ ```bash
123
+ jam doctor # checks Node version, config, provider connectivity, ripgrep
124
+ jam auth login # validates connection to Ollama
125
+ ```
126
+
127
+ ---
128
+
129
+ ## Commands
130
+
131
+ ### `jam ask`
132
+
133
+ One-shot question. Streams the response to stdout.
134
+
135
+ ```bash
136
+ jam ask "What is the difference between TCP and UDP?"
137
+
138
+ # From stdin
139
+ echo "Explain recursion in one paragraph" | jam ask
140
+
141
+ # From a file
142
+ jam ask --file prompt.txt
143
+
144
+ # JSON output (full response + token usage)
145
+ jam ask "What is 2+2?" --json
146
+
147
+ # Override model
148
+ jam ask "Hello" --model codellama
149
+
150
+ # Use a named profile
151
+ jam ask "Hello" --profile work
152
+ ```
153
+
154
+ **Options:**
155
+
156
+ | Flag | Description |
157
+ |------|-------------|
158
+ | `--file <path>` | Read prompt from file |
159
+ | `--system <prompt>` | Override system prompt |
160
+ | `--json` | Machine-readable JSON output |
161
+ | `--model <id>` | Override model for this request |
162
+ | `--provider <name>` | Override provider |
163
+ | `--base-url <url>` | Override provider base URL |
164
+ | `--profile <name>` | Use a named config profile |
165
+ | `--no-color` | Strip ANSI colors from output |
166
+
167
+ ---
168
+
169
+ ### `jam chat`
170
+
171
+ Interactive multi-turn chat REPL (Ink/React TUI).
172
+
173
+ ```bash
174
+ jam chat # new session
175
+ jam chat --name "auth refactor" # named session
176
+ jam chat --resume <sessionId> # resume a previous session
177
+ ```
178
+
179
+ **Keyboard shortcuts inside chat:**
180
+
181
+ | Key | Action |
182
+ |-----|--------|
183
+ | `Enter` | Submit message |
184
+ | `Ctrl-C` (once) | Interrupt current generation |
185
+ | `Ctrl-C` (twice) | Exit chat |
186
+
187
+ Sessions are saved automatically to `~/.local/share/jam/sessions/` (macOS: `~/Library/Application Support/jam/sessions/`).
188
+
189
+ ---
190
+
191
+ ### `jam explain`
192
+
193
+ Read one or more files and ask the model to explain them.
194
+
195
+ ```bash
196
+ jam explain src/auth/middleware.ts
197
+ jam explain src/api/routes.ts src/api/handlers.ts
198
+ jam explain src/utils/retry.ts --json
199
+ ```
200
+
201
+ ---
202
+
203
+ ### `jam search`
204
+
205
+ Search the codebase using ripgrep (falls back to JS if `rg` is not installed).
206
+
207
+ ```bash
208
+ jam search "TODO" # plain search, prints results
209
+ jam search "useEffect" --glob "*.tsx" # filter by file type
210
+ jam search "createServer" --ask # pipe results to AI for explanation
211
+ jam search "error handling" --max-results 50
212
+ ```
213
+
214
+ **Options:**
215
+
216
+ | Flag | Description |
217
+ |------|-------------|
218
+ | `--glob <pattern>` | Limit to files matching this glob (e.g. `*.ts`) |
219
+ | `--max-results <n>` | Max results (default: 20) |
220
+ | `--ask` | Send results to AI for analysis |
221
+ | `--json` | JSON output (with `--ask`) |
222
+
223
+ ---
224
+
225
+ ### `jam diff`
226
+
227
+ Run `git diff` and optionally review it with AI.
228
+
229
+ ```bash
230
+ jam diff # review working tree changes
231
+ jam diff --staged # review staged changes (ready to commit)
232
+ jam diff --path src/api/ # limit to a specific directory
233
+ jam diff --no-review # just print the raw diff, no AI
234
+ jam diff --staged --json # JSON output
235
+ ```
236
+
237
+ ---
238
+
239
+ ### `jam patch`
240
+
241
+ Ask the AI to generate a unified diff patch, validate it, and optionally apply it.
242
+
243
+ ```bash
244
+ jam patch "Add input validation to the login function"
245
+ jam patch "Fix the off-by-one error in pagination" --file src/api/paginate.ts
246
+ jam patch "Add JSDoc comments to all public methods" --dry # generate only, don't apply
247
+ jam patch "Remove unused imports" --yes # auto-confirm apply
248
+ ```
249
+
250
+ **Flow:**
251
+ 1. Collects context (git status, current diff, specified files)
252
+ 2. Prompts the model for a unified diff
253
+ 3. Validates with `git apply --check`
254
+ 4. Shows the patch preview
255
+ 5. Asks for confirmation (unless `--yes`)
256
+ 6. Applies with `git apply`
257
+
258
+ ---
259
+
260
+ ### `jam run`
261
+
262
+ Agentic task workflow — the model can call tools in a loop to accomplish a goal.
263
+
264
+ ```bash
265
+ jam run "Find all TODO comments and summarize them"
266
+ jam run "Check git status and explain what's changed"
267
+ jam run "Read src/config.ts and identify any security issues"
268
+ ```
269
+
270
+ **Available tools (model-callable):**
271
+
272
+ | Tool | Type | Description |
273
+ |------|------|-------------|
274
+ | `read_file` | Read | Read file contents |
275
+ | `list_dir` | Read | List directory contents |
276
+ | `search_text` | Read | Search codebase with ripgrep |
277
+ | `git_status` | Read | Get git status |
278
+ | `git_diff` | Read | Get git diff |
279
+ | `write_file` | **Write** | Write to a file (prompts for confirmation) |
280
+ | `apply_patch` | **Write** | Apply a unified diff (prompts for confirmation) |
281
+
282
+ Write tools require confirmation unless `toolPolicy` is set to `allowlist` in config.
283
+
284
+ ---
285
+
286
+ ### `jam auth`
287
+
288
+ ```bash
289
+ jam auth login # validate connectivity to the current provider
290
+ jam auth logout # remove stored credentials from keychain
291
+ ```
292
+
293
+ ---
294
+
295
+ ### `jam config`
296
+
297
+ ```bash
298
+ jam config show # print merged effective config as JSON
299
+ jam config init # create .jam/config.json in the current directory
300
+ jam config init --global # create ~/.config/jam/config.json
301
+ ```
302
+
303
+ ---
304
+
305
+ ### `jam models list`
306
+
307
+ ```bash
308
+ jam models list # list models available from the current provider
309
+ jam models list --provider ollama --base-url http://localhost:11434
310
+ ```
311
+
312
+ ---
313
+
314
+ ### `jam history`
315
+
316
+ ```bash
317
+ jam history list # list all saved chat sessions
318
+ jam history show <id> # show all messages in a session (first 8 chars of ID work)
319
+ ```
320
+
321
+ ---
322
+
323
+ ### `jam completion install`
324
+
325
+ ```bash
326
+ jam completion install # auto-detects shell
327
+ jam completion install --shell bash # bash completion script
328
+ jam completion install --shell zsh # zsh completion script
329
+ ```
330
+
331
+ Follow the printed instructions to add the completion to your shell.
332
+
333
+ ---
334
+
335
+ ### `jam doctor`
336
+
337
+ Run system diagnostics:
338
+
339
+ ```bash
340
+ jam doctor
341
+ ```
342
+
343
+ Checks:
344
+ - Node.js version (≥ 20)
345
+ - Config file is valid
346
+ - Provider connectivity (Ollama reachable)
347
+ - ripgrep availability (optional, JS fallback used if absent)
348
+ - keytar availability (optional, env vars used if absent)
349
+
350
+ ---
351
+
352
+ ## Configuration
353
+
354
+ ### Config File Locations
355
+
356
+ Jam merges config in priority order (highest wins):
357
+
358
+ ```
359
+ 1. CLI flags
360
+ 2. .jam/config.json or .jamrc (repo-level)
361
+ 3. ~/.config/jam/config.json (user-level)
362
+ 4. Built-in defaults
363
+ ```
364
+
365
+ ### Config Schema
366
+
367
+ ```json
368
+ {
369
+ "defaultProfile": "default",
370
+ "profiles": {
371
+ "default": {
372
+ "provider": "ollama",
373
+ "model": "llama3.2",
374
+ "baseUrl": "http://localhost:11434",
375
+ "temperature": 0.7,
376
+ "maxTokens": 4096,
377
+ "systemPrompt": "You are a helpful coding assistant."
378
+ },
379
+ "fast": {
380
+ "provider": "ollama",
381
+ "model": "qwen2.5-coder:1.5b",
382
+ "baseUrl": "http://localhost:11434"
383
+ }
384
+ },
385
+ "toolPolicy": "ask_every_time",
386
+ "toolAllowlist": [],
387
+ "historyEnabled": true,
388
+ "logLevel": "warn",
389
+ "redactPatterns": ["sk-[a-z0-9]+", "Bearer\\s+\\S+"]
390
+ }
391
+ ```
392
+
393
+ ### Config Fields
394
+
395
+ | Field | Type | Default | Description |
396
+ |-------|------|---------|-------------|
397
+ | `defaultProfile` | string | `"default"` | Active profile name |
398
+ | `profiles` | object | see below | Named provider/model configurations |
399
+ | `toolPolicy` | `ask_every_time` \| `allowlist` \| `never` | `ask_every_time` | How write tools require confirmation |
400
+ | `toolAllowlist` | string[] | `[]` | Tools that never prompt (when policy is `allowlist`) |
401
+ | `historyEnabled` | boolean | `true` | Save chat sessions to disk |
402
+ | `logLevel` | `silent` \| `error` \| `warn` \| `info` \| `debug` | `warn` | Log verbosity |
403
+ | `redactPatterns` | string[] | `[]` | Regex patterns redacted from logs |
404
+
405
+ ### Profile Fields
406
+
407
+ | Field | Type | Description |
408
+ |-------|------|-------------|
409
+ | `provider` | string | Provider name (`ollama`) |
410
+ | `model` | string | Model ID (e.g. `llama3.2`, `codellama`) |
411
+ | `baseUrl` | string | Provider API base URL |
412
+ | `apiKey` | string | API key (prefer keychain or env vars) |
413
+ | `temperature` | number | Sampling temperature (0–2) |
414
+ | `maxTokens` | number | Max tokens in response |
415
+ | `systemPrompt` | string | Default system prompt |
416
+
417
+ ### Initialize Config
418
+
419
+ ```bash
420
+ # Repo-level (committed to version control)
421
+ jam config init
422
+
423
+ # User-level (applies everywhere)
424
+ jam config init --global
425
+ ```
426
+
427
+ ### Using Profiles
428
+
429
+ ```bash
430
+ # Use a specific profile
431
+ jam ask "Hello" --profile fast
432
+
433
+ # Switch default in config
434
+ echo '{"defaultProfile": "fast"}' > .jamrc
435
+ ```
436
+
437
+ ---
438
+
439
+ ## Environment Variables
440
+
441
+ | Variable | Description |
442
+ |----------|-------------|
443
+ | `JAM_API_KEY` | API key fallback (if keytar unavailable) |
444
+ | `JAM_BASE_URL` | Override provider base URL |
445
+
446
+ ---
447
+
448
+ ## Development
449
+
450
+ ```bash
451
+ npm run dev -- ask "What is 2+2?" # run from source with tsx
452
+ npm run build # compile TypeScript to dist/
453
+ npm run typecheck # tsc --noEmit
454
+ npm run lint # ESLint
455
+ npm test # Vitest unit tests
456
+ npm run test:watch # watch mode
457
+ npm run test:coverage # coverage report
458
+ ```
459
+
460
+ ### Project Structure
461
+
462
+ ```
463
+ src/
464
+ ├── index.ts # CLI entry point (commander, lazy imports)
465
+ ├── commands/ # One file per command
466
+ │ ├── ask.ts # jam ask
467
+ │ ├── chat.ts # jam chat
468
+ │ ├── run.ts # jam run (agentic loop)
469
+ │ ├── explain.ts # jam explain
470
+ │ ├── search.ts # jam search
471
+ │ ├── diff.ts # jam diff
472
+ │ ├── patch.ts # jam patch
473
+ │ ├── auth.ts # jam auth
474
+ │ ├── config.ts # jam config
475
+ │ ├── models.ts # jam models
476
+ │ ├── history.ts # jam history
477
+ │ ├── completion.ts # jam completion
478
+ │ └── doctor.ts # jam doctor
479
+ ├── providers/ # LLM adapter layer
480
+ │ ├── base.ts # ProviderAdapter interface
481
+ │ ├── ollama.ts # Ollama adapter (NDJSON streaming)
482
+ │ └── factory.ts # createProvider()
483
+ ├── tools/ # Model-callable local tools
484
+ │ ├── types.ts # ToolDefinition, ToolResult interfaces
485
+ │ ├── registry.ts # ToolRegistry + permission enforcement
486
+ │ ├── read_file.ts
487
+ │ ├── list_dir.ts
488
+ │ ├── search_text.ts
489
+ │ ├── git_diff.ts
490
+ │ ├── git_status.ts
491
+ │ ├── apply_patch.ts
492
+ │ └── write_file.ts
493
+ ├── config/ # Config loading and schema
494
+ │ ├── schema.ts # Zod schema
495
+ │ ├── defaults.ts # Built-in defaults
496
+ │ └── loader.ts # cosmiconfig + deep merge
497
+ ├── storage/
498
+ │ └── history.ts # Chat session persistence (JSON files)
499
+ ├── ui/
500
+ │ ├── chat.tsx # Ink chat REPL (React TUI)
501
+ │ └── renderer.ts # Markdown + streaming renderer
502
+ └── utils/
503
+ ├── errors.ts # JamError class
504
+ ├── stream.ts # withRetry, collectStream
505
+ ├── logger.ts # Logger (stderr, redaction)
506
+ ├── secrets.ts # keytar + env fallback
507
+ └── workspace.ts # Git root detection
508
+ ```
509
+
510
+ ---
511
+
512
+ ## Adding a New Provider
513
+
514
+ 1. Implement `ProviderAdapter` from `src/providers/base.ts`:
515
+
516
+ ```typescript
517
+ import type { ProviderAdapter, ProviderInfo, CompletionRequest, StreamChunk } from './base.js';
518
+
519
+ export class MyProvider implements ProviderAdapter {
520
+ readonly info: ProviderInfo = { name: 'myprovider', supportsStreaming: true };
521
+
522
+ async validateCredentials(): Promise<void> { /* ... */ }
523
+ async listModels(): Promise<string[]> { /* ... */ }
524
+ async *streamCompletion(request: CompletionRequest): AsyncIterable<StreamChunk> { /* ... */ }
525
+ }
526
+ ```
527
+
528
+ 2. Register in `src/providers/factory.ts`:
529
+
530
+ ```typescript
531
+ if (provider === 'myprovider') {
532
+ const { MyProvider } = await import('./myprovider.js');
533
+ return new MyProvider({ apiKey: profile.apiKey });
534
+ }
535
+ ```
536
+
537
+ 3. Use: `jam ask "Hello" --provider myprovider`
538
+
539
+ ---
540
+
541
+ ## Contributing
542
+
543
+ Jam is intentionally built to be easy to extend. The architecture is layered, each concern is isolated, and the three main contribution surfaces — providers, tools, and commands — each have a clean interface to implement.
544
+
545
+ **You don't need to understand the whole codebase to contribute.** A new provider is one file. A new tool is one file. The patterns are already established and documented.
546
+
547
+ 1. **Fork** the repository
548
+ 2. **Create** your feature branch (`git checkout -b feat/amazing-feature`)
549
+ 3. **Commit** your changes (`git commit -m 'feat: add amazing feature'`)
550
+ 4. **Push** to the branch (`git push origin feat/amazing-feature`)
551
+ 5. **Open** a Pull Request
552
+
553
+ Please read our [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct, development workflow, and pull request process.
554
+
555
+ ### Good First Issues
556
+
557
+ Look for issues labeled [`good first issue`](https://github.com/sunilp/jam-cli/labels/good%20first%20issue) — these are great starting points for new contributors.
558
+
559
+ ### What the Codebase Looks Like
560
+
561
+ - **Strict TypeScript throughout** — no `any`, no guessing what a function does
562
+ - **Tests colocated with source** — `foo.ts` → `foo.test.ts`, using Vitest
563
+ - **One file per concern** — each command, provider, and tool is self-contained
564
+ - **Zod schema validation** — config is validated at load time, not at runtime when it's too late
565
+ - **Conventional Commits** — the git log tells the story of the project
566
+
567
+ If you can read TypeScript, you can contribute to Jam.
568
+
569
+ ---
570
+
571
+ ## Community
572
+
573
+ - **Issues** — [Report bugs or request features](https://github.com/sunilp/jam-cli/issues)
574
+ - **Discussions** — [Ask questions, share ideas](https://github.com/sunilp/jam-cli/discussions)
575
+ - **Code of Conduct** — [Our community standards](CODE_OF_CONDUCT.md)
576
+
577
+ ---
578
+
579
+ ## Security Policy
580
+
581
+ We take security seriously. If you discover a vulnerability, please **do not** open a public issue. Instead, follow the responsible disclosure process in our [Security Policy](SECURITY.md).
582
+
583
+ ---
584
+
585
+ ## Roadmap
586
+
587
+ - [ ] OpenAI / Azure OpenAI provider
588
+ - [ ] Anthropic Claude provider
589
+ - [ ] Groq provider
590
+ - [ ] `jam commit` — AI-generated commit messages
591
+ - [ ] `jam review` — PR review workflow
592
+ - [ ] Plugin system for custom tools
593
+ - [ ] Token usage tracking and budgets
594
+ - [ ] Web UI companion
595
+
596
+ ---
597
+
598
+ ## Acknowledgments
599
+
600
+ Built with these excellent open source projects:
601
+
602
+ - [Commander.js](https://github.com/tj/commander.js) — CLI framework
603
+ - [Ink](https://github.com/vadimdemedes/ink) — React for CLIs
604
+ - [Ollama](https://ollama.ai) — Local LLM serving
605
+ - [Zod](https://zod.dev) — Schema validation
606
+ - [marked](https://github.com/markedjs/marked) — Markdown rendering
607
+ - [cosmiconfig](https://github.com/cosmiconfig/cosmiconfig) — Configuration loading
608
+
609
+ ---
610
+
611
+ ## License
612
+
613
+ MIT License — Copyright (c) 2026-present **Sunil Prakash**. All rights reserved.
614
+
615
+ See [LICENSE](LICENSE) for the full license text.
616
+
617
+ ---
618
+
619
+ <div align="center">
620
+
621
+ **Made with ❤️ by [Sunil Prakash](https://github.com/sunilp)**
622
+
623
+ If you find Jam useful, consider giving it a ⭐ on GitHub — it helps others discover the project!
624
+
625
+ </div>
@@ -0,0 +1,9 @@
1
+ import type { CliOverrides } from '../config/schema.js';
2
+ export interface AskOptions extends CliOverrides {
3
+ file?: string;
4
+ json?: boolean;
5
+ noColor?: boolean;
6
+ system?: string;
7
+ }
8
+ export declare function runAsk(inlinePrompt: string | undefined, options: AskOptions): Promise<void>;
9
+ //# sourceMappingURL=ask.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask.d.ts","sourceRoot":"","sources":["../../src/commands/ask.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,WAAW,UAAW,SAAQ,YAAY;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAcD,wBAAsB,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAyEjG"}