codeep 2.15.0 → 2.16.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.
package/README.md CHANGED
@@ -89,15 +89,19 @@ When started in a project directory, Codeep automatically:
89
89
  - Press Enter to send, Escape to cancel
90
90
  - Works reliably in all terminals (no Ctrl+V issues)
91
91
 
92
- ### File Context (`/add`, `/drop`)
92
+ ### File Context (`/add`, `/drop`, `@mentions`)
93
93
  Explicitly add files to the conversation context:
94
94
 
95
95
  - **`/add <path>`** - Add one or more files to context
96
96
  - **`/add`** (no args) - Show currently added files
97
97
  - **`/drop <path>`** - Remove a specific file from context
98
98
  - **`/drop`** (no args) - Remove all files from context
99
+ - **`@path/to/file`** - Inline mention: type `@` followed by a file path anywhere in your message and its contents are attached for that message only. Supports relative paths (`@src/index.ts`), absolute (`@/etc/hosts`), home (`@~/.codeep/profile.md`), and quoted paths with spaces (`@"my file.ts"`). In the CLI, typing `@` opens an autocomplete file picker — ↑↓ to navigate, Tab to insert.
100
+ - **`@folder <path>`** (alias `@dir`) - Attach an entire directory: type `@folder src/components` and every source file under it is loaded recursively. Skips `node_modules`, `.git`, `dist`, binary extensions (images, archives, lockfiles), and files over the per-file size cap. Stops at a 200 KB total cap per mention (with a notification when it hits the limit). Quoted paths supported: `@folder "my components"`.
101
+ - **`@web <url>`** - Inline web fetch: type `@web https://example.com/docs` (or `@web example.com/docs`) and the page is fetched, converted to readable text, and attached to the message. HTML is stripped; plain text and JSON pass through as-is. Capped at 32 KB, 12 s timeout. Successful fetches are cached for 30 min (per session, up to 50 entries) so repeated `@web` for the same URL is instant and free; use `/web-cache clear` to reset.
102
+ - **`@git <ref>`** - Inline git context: type `@git diff`, `@git diff --staged`, `@git HEAD`, `@git <sha>`, `@git main:src/x.ts`, or `@git diff a..b` to inject that diff / commit / file-at-ref into the message as a `[Git ref]` block. Capped at 64 KB per mention (truncated with a marker). Unknown refs surface a friendly failure note.
99
103
 
100
- Added files are automatically attached to every message (both chat and agent mode) until dropped. Useful for giving the AI specific files to work with.
104
+ Added files (via `/add`) are automatically attached to every message (both chat and agent mode) until dropped. `@mentions` are per-message — handy for one-off references without polluting the persistent context.
101
105
 
102
106
  ```
103
107
  > /add src/utils/api.ts src/types/index.ts
@@ -106,6 +110,10 @@ Added 2 file(s) to context (2 total)
106
110
  > refactor the API client to use async/await
107
111
  # AI sees both files attached to your message
108
112
 
113
+ > review @src/auth/login.ts for security issues
114
+ Loaded 1 file(s) from @mentions
115
+ # AI sees login.ts attached for this message only
116
+
109
117
  > /drop
110
118
  Dropped all 2 file(s) from context
111
119
  ```
@@ -1043,7 +1051,8 @@ After installation, `codeep` is available globally in your terminal. Simply run
1043
1051
 
1044
1052
  | Command | Description |
1045
1053
  |---------|-------------|
1046
- | `/apply` | Apply file changes from AI response |
1054
+ | `/apply` | Apply file changes from AI response (shows hunk counts; `--only file.ts:0,1` for selective apply, `--interactive`/`-i` for per-hunk review) |
1055
+ | `/web-cache` | Show `@web` fetch cache stats (alias `/web-cache clear` to reset) |
1047
1056
  | `/copy [n]` | Copy code block to clipboard (n = block number, -1 = last) |
1048
1057
  | `/paste` | Paste content from clipboard into chat |
1049
1058
  | `/add <path>` | Add file(s) to conversation context |
@@ -87,11 +87,32 @@ export function buildRawOutput(toolName, params, toolResult) {
87
87
  }
88
88
  export async function runAgentSession(opts) {
89
89
  const projectContext = buildProjectContext(opts.workspaceRoot);
90
+ // Expand `@folder`/`@file`/`@git` mentions in the user prompt, the
91
+ // same way the TUI does (see src/renderer/main.ts). ACP clients
92
+ // (VS Code / Zed) get the same inline-context UX. `@web` is async
93
+ // and fetched here too.
94
+ let enrichedPrompt = opts.prompt;
95
+ try {
96
+ const { expandFileAndFolderMentions, expandGitMentions } = await import('../utils/mentions.js');
97
+ const { expandWebMentions } = await import('../utils/webFetch.js');
98
+ const fileResult = expandFileAndFolderMentions(enrichedPrompt, { root: opts.workspaceRoot });
99
+ const gitResult = await expandGitMentions(fileResult.enrichedPrompt, { root: opts.workspaceRoot });
100
+ const webResult = await expandWebMentions(gitResult.enrichedPrompt);
101
+ enrichedPrompt = webResult.enrichedPrompt;
102
+ // Surface failures as thoughts so the editor shows them.
103
+ const allFailures = [...fileResult.failures, ...gitResult.failures, ...webResult.failures];
104
+ if (allFailures.length > 0 && opts.onThought) {
105
+ opts.onThought(allFailures.map((f) => `${f.mention}: ${f.reason}`).join(' · '));
106
+ }
107
+ }
108
+ catch {
109
+ // Mention expansion is best-effort — never block the agent run.
110
+ }
90
111
  let toolCallCounter = 0;
91
112
  // Maps tool call key → ACP toolCallId so onToolResult can emit finished/error status
92
113
  const toolCallIdMap = new Map();
93
114
  let chunksEmitted = 0;
94
- const result = await runAgent(opts.prompt, projectContext, {
115
+ const result = await runAgent(enrichedPrompt, projectContext, {
95
116
  abortSignal: opts.abortSignal,
96
117
  onChunk: (text) => { chunksEmitted++; opts.onChunk(text); },
97
118
  onIteration: (_iteration, message) => {
@@ -232,18 +232,21 @@ export const PROVIDERS = {
232
232
  openai: { baseUrl: 'https://api.moonshot.ai/v1', authHeader: 'Bearer', supportsNativeTools: true },
233
233
  },
234
234
  models: [
235
- { id: 'kimi-k2.7-code', name: 'Kimi K2.7 Code', description: 'Flagship agentic coding model (256K context)' },
235
+ { id: 'kimi-k3-code', name: 'Kimi K3 Code', description: 'Newest flagship agentic coding model (1M context, deep reasoning)' },
236
+ { id: 'kimi-k3-code-highspeed', name: 'Kimi K3 Code (High-Speed)', description: 'Throughput-tuned K3 Code for latency-sensitive loops' },
237
+ { id: 'kimi-k3-thinking', name: 'Kimi K3 Thinking', description: 'K3 with explicit reasoning traces (highest quality, slower)' },
238
+ { id: 'kimi-k2.7-code', name: 'Kimi K2.7 Code', description: 'Previous-gen flagship agentic coding model (256K context)' },
236
239
  { id: 'kimi-k2.7-code-highspeed', name: 'Kimi K2.7 Code (High-Speed)', description: 'Throughput-tuned K2.7 Code for latency-sensitive loops' },
237
240
  { id: 'kimi-k2.6', name: 'Kimi K2.6', description: 'Previous-gen multimodal reasoning model' },
238
241
  { id: 'kimi-k2.5', name: 'Kimi K2.5', description: 'Older general-purpose model (cheaper)' },
239
242
  ],
240
- defaultModel: 'kimi-k2.7-code',
243
+ defaultModel: 'kimi-k3-code',
241
244
  defaultProtocol: 'openai',
242
- maxOutputTokens: 32_768,
245
+ maxOutputTokens: 65_536,
243
246
  envKey: 'MOONSHOT_API_KEY',
244
247
  subscribeUrl: 'https://platform.kimi.ai/console/api-keys',
245
248
  groupLabel: 'Kimi — API (pay-per-use)',
246
- hint: 'Pay-per-use via Moonshot API key (platform.kimi.ai).',
249
+ hint: 'Pay-per-use via Moonshot API key (platform.kimi.ai). K3 models support 1M context and explicit reasoning.',
247
250
  },
248
251
  'kimi-cn': {
249
252
  name: 'Kimi China (Moonshot)',
@@ -252,18 +255,21 @@ export const PROVIDERS = {
252
255
  openai: { baseUrl: 'https://api.moonshot.cn/v1', authHeader: 'Bearer', supportsNativeTools: true },
253
256
  },
254
257
  models: [
255
- { id: 'kimi-k2.7-code', name: 'Kimi K2.7 Code', description: 'Flagship agentic coding model (256K context)' },
258
+ { id: 'kimi-k3-code', name: 'Kimi K3 Code', description: 'Newest flagship agentic coding model (1M context, deep reasoning)' },
259
+ { id: 'kimi-k3-code-highspeed', name: 'Kimi K3 Code (High-Speed)', description: 'Throughput-tuned K3 Code' },
260
+ { id: 'kimi-k3-thinking', name: 'Kimi K3 Thinking', description: 'K3 with explicit reasoning traces' },
261
+ { id: 'kimi-k2.7-code', name: 'Kimi K2.7 Code', description: 'Previous-gen flagship agentic coding model (256K context)' },
256
262
  { id: 'kimi-k2.7-code-highspeed', name: 'Kimi K2.7 Code (High-Speed)', description: 'Throughput-tuned K2.7 Code' },
257
263
  { id: 'kimi-k2.6', name: 'Kimi K2.6', description: 'Previous-gen multimodal reasoning model' },
258
264
  { id: 'kimi-k2.5', name: 'Kimi K2.5', description: 'Older general-purpose model' },
259
265
  ],
260
- defaultModel: 'kimi-k2.7-code',
266
+ defaultModel: 'kimi-k3-code',
261
267
  defaultProtocol: 'openai',
262
- maxOutputTokens: 32_768,
268
+ maxOutputTokens: 65_536,
263
269
  envKey: 'MOONSHOT_CN_API_KEY',
264
270
  subscribeUrl: 'https://platform.moonshot.cn/console/api-keys',
265
271
  groupLabel: 'Kimi China — API (pay-per-use)',
266
- hint: 'Pay-per-use via Moonshot China API key (platform.moonshot.cn).',
272
+ hint: 'Pay-per-use via Moonshot China API key (platform.moonshot.cn). K3 models support 1M context.',
267
273
  },
268
274
  // ── Grok (xAI) ────────────────────────────────────────────────────
269
275
  // Pay-per-use today (console.x.ai key). The SuperGrok / X Premium+
@@ -433,11 +439,11 @@ export const PROVIDERS = {
433
439
  },
434
440
  models: [
435
441
  { id: 'claude-fable-5', name: 'Claude Fable 5', description: 'Most capable — hardest reasoning & long-horizon agentic work' },
436
- { id: 'claude-opus-4-8', name: 'Claude Opus 4.8', description: 'Most capable Opus model' },
442
+ { id: 'claude-opus-5', name: 'Claude Opus 5', description: 'Complex agentic coding & deep reasoning — the Opus workhorse' },
437
443
  { id: 'claude-sonnet-5', name: 'Claude Sonnet 5', description: 'Best balance of speed and intelligence' },
438
444
  { id: 'claude-haiku-4-5-20251001', name: 'Claude Haiku', description: 'Fastest and most affordable' },
439
445
  ],
440
- defaultModel: 'claude-opus-4-8',
446
+ defaultModel: 'claude-opus-5',
441
447
  defaultProtocol: 'anthropic',
442
448
  envKey: 'ANTHROPIC_API_KEY',
443
449
  groupLabel: 'Anthropic',
@@ -666,8 +672,8 @@ export function providerNoStreamWithTools(providerId) {
666
672
  * internally and 400 on any custom value, so they're here too.
667
673
  */
668
674
  const SAMPLING_PARAMS_REJECTED = [
669
- 'claude-fable-5', 'claude-opus-4-8', 'claude-opus-4-7', 'claude-sonnet-5',
670
- 'kimi-k2.7-code', 'kimi-for-coding',
675
+ 'claude-fable-5', 'claude-opus-5', 'claude-opus-4-8', 'claude-opus-4-7', 'claude-sonnet-5',
676
+ 'kimi-k3-code', 'kimi-k3-thinking', 'kimi-k2.7-code', 'kimi-for-coding',
671
677
  ];
672
678
  export function modelRejectsSamplingParams(model) {
673
679
  return SAMPLING_PARAMS_REJECTED.some(id => model === id || model.startsWith(`${id}-`));
@@ -709,10 +715,10 @@ export function modelSupportsReasoningEffort(providerId, model) {
709
715
  const id = canonicalModelId(model);
710
716
  switch (providerId) {
711
717
  case 'anthropic':
712
- // Effort is GA on Opus 4.5+, Sonnet 4.6/5, Fable 5 — NOT Haiku or Sonnet 4.5.
718
+ // Effort is GA on Opus 5, Opus 4.5+, Sonnet 4.6/5, Fable 5 — NOT Haiku or Sonnet 4.5.
713
719
  if (idMatches(id, 'claude-haiku-4-5') || idMatches(id, 'claude-sonnet-4-5'))
714
720
  return false;
715
- return /^claude-(opus-4-([5-9]|\d\d)|sonnet-(4-6|5)|fable-5)/.test(id);
721
+ return /^claude-(opus-5|opus-4-([5-9]|\d\d)|sonnet-(4-6|5)|fable-5)/.test(id);
716
722
  case 'openai':
717
723
  // GPT-5.x are reasoning models — reasoning_effort across the family (incl. mini).
718
724
  return id.startsWith('gpt-5');
@@ -20,6 +20,37 @@ export interface ConfirmOptions {
20
20
  onConfirm: () => void;
21
21
  onCancel?: () => void;
22
22
  }
23
+ /**
24
+ * One hunk in the interactive `/apply --interactive` picker.
25
+ * `lines` are already-formatted diff lines (e.g. `+ added`, `- removed`).
26
+ */
27
+ export interface HunkPickerItem {
28
+ /** File path this hunk belongs to. */
29
+ path: string;
30
+ /** 0-based hunk index within the file diff. */
31
+ hunkIndex: number;
32
+ /** Human-readable hunk header, e.g. `@@ -12,3 +12,5 @@`. */
33
+ header: string;
34
+ /** Pre-formatted diff lines to display. */
35
+ lines: string[];
36
+ }
37
+ /**
38
+ * Options for the interactive hunk picker. The picker walks the user
39
+ * through `items` one at a time; for each they accept (`y`/Enter) or
40
+ * skip (`n`). `a` accepts all remaining, `q`/Esc quits.
41
+ *
42
+ * `onComplete` fires once with the set of accepted `[path, hunkIndex]`
43
+ * pairs (possibly empty) so the caller can apply them via
44
+ * `applyHunksToFiles`.
45
+ */
46
+ export interface HunkPickerOptions {
47
+ title: string;
48
+ items: HunkPickerItem[];
49
+ onComplete: (accepted: Array<{
50
+ path: string;
51
+ hunkIndex: number;
52
+ }>) => void;
53
+ }
23
54
  export interface AppOptions {
24
55
  onSubmit: (message: string) => Promise<void>;
25
56
  onCommand: (command: string, args: string[]) => void;
@@ -29,6 +60,8 @@ export interface AppOptions {
29
60
  getStatus: () => StatusInfo;
30
61
  hasWriteAccess?: () => boolean;
31
62
  hasProjectContext?: () => boolean;
63
+ /** Project root for `@mention` autocomplete suggestions. Falls back to cwd. */
64
+ getProjectRoot?: () => string;
32
65
  }
33
66
  export declare class App {
34
67
  private screen;
@@ -67,9 +100,19 @@ export declare class App {
67
100
  private showAutocomplete;
68
101
  private autocompleteIndex;
69
102
  private autocompleteItems;
103
+ private showMentionAutocomplete;
104
+ private mentionIndex;
105
+ private mentionItems;
106
+ private mentionAtStart;
107
+ /** Project root for resolving `suggestMentions`. Cached per update. */
108
+ private mentionRoot;
70
109
  private confirmOpen;
71
110
  private confirmOptions;
72
111
  private confirmSelection;
112
+ private hunkPickerOpen;
113
+ private hunkPickerOptions;
114
+ private hunkPickerIndex;
115
+ private hunkPickerAccepted;
73
116
  private menuOpen;
74
117
  private menuTitle;
75
118
  /** Filtered view shown to the user; derived from `menuItemsAll` + `menuFilter`. */
@@ -231,6 +274,11 @@ export declare class App {
231
274
  * Show confirmation dialog
232
275
  */
233
276
  showConfirm(options: ConfirmOptions): void;
277
+ /**
278
+ * Show the interactive hunk picker (`/apply --interactive`).
279
+ * The caller passes pre-built items + an `onComplete` callback.
280
+ */
281
+ showHunkPicker(options: HunkPickerOptions): void;
234
282
  /**
235
283
  * Show permission dialog (inline, below status bar)
236
284
  */
@@ -314,6 +362,13 @@ export declare class App {
314
362
  * Update autocomplete suggestions
315
363
  */
316
364
  private updateAutocomplete;
365
+ /**
366
+ * Replace the in-progress `@query` (from `mentionAtStart` to the
367
+ * cursor) with the selected mention's path. Keeps the `@` prefix and
368
+ * positions the cursor right after the inserted path so the user can
369
+ * keep typing the rest of the message.
370
+ */
371
+ private applyMentionSelection;
317
372
  /**
318
373
  * Handle inline status keys
319
374
  */
@@ -352,6 +407,15 @@ export declare class App {
352
407
  private handleInlinePermissionKey;
353
408
  private handleInlineSessionPickerKey;
354
409
  private handleInlineConfirmKey;
410
+ /**
411
+ * Handle keys in the interactive hunk picker.
412
+ * y / Enter / → accept this hunk, advance
413
+ * n / ← skip this hunk, advance
414
+ * a accept this + all remaining, finish
415
+ * q / Esc finish without accepting this hunk
416
+ * ↑ / ↓ navigate (preview only — no decision)
417
+ */
418
+ private handleHunkPickerKey;
355
419
  /**
356
420
  * Submit the current input buffer (used by Enter and Escape-in-multiline)
357
421
  */
@@ -373,6 +437,11 @@ export declare class App {
373
437
  * Render inline confirmation dialog below status bar
374
438
  */
375
439
  private renderInlineConfirm;
440
+ /**
441
+ * Render inline hunk picker (`/apply --interactive`).
442
+ * Shows the current hunk's diff + the y/n/a/q key legend.
443
+ */
444
+ private renderInlineHunkPicker;
376
445
  /**
377
446
  * Render input line
378
447
  */
@@ -394,6 +463,14 @@ export declare class App {
394
463
  * Render inline autocomplete below status bar
395
464
  */
396
465
  private renderInlineAutocomplete;
466
+ /**
467
+ * Render inline `@mention` file picker below the status bar.
468
+ *
469
+ * Mirrors the layout of `renderInlineAutocomplete` (separator → title →
470
+ * items → footer) but shows file paths with their parent directory as
471
+ * the description, and a `@` prefix instead of `/`.
472
+ */
473
+ private renderInlineMentionPicker;
397
474
  /**
398
475
  * Render inline permission dialog
399
476
  */