git-coco 0.32.0 → 0.34.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
@@ -10,7 +10,7 @@
10
10
  [![Last Commit](https://img.shields.io/github/last-commit/gfargo/coco)](https://github.com/gfargo/coco/tree/main)
11
11
  [![Discord](https://img.shields.io/discord/1176716060825767948)](https://discord.gg/KGu9nE9Ejx)
12
12
 
13
- An AI-powered git assistant that generates meaningful commit messages, creates changelogs, and streamlines your development workflow.
13
+ An AI-powered git assistant that generates meaningful commit messages, creates changelogs, explores repository history, and streamlines your development workflow.
14
14
 
15
15
  **✨ Key Features:**
16
16
 
@@ -18,6 +18,7 @@ An AI-powered git assistant that generates meaningful commit messages, creates c
18
18
  - 📋 **Conventional Commits** - Full support with automatic validation and formatting
19
19
  - 🔧 **Commitlint Integration** - Seamless integration with your existing commitlint configuration
20
20
  - 🏠 **Local AI Support** - Run completely offline with Ollama (no API costs, full privacy)
21
+ - 🖥️ **Coco UI Git Workstation** - Seven top-level views (history, status, diff, compose, branches, tags, stash) reachable via `g`-prefixed chords, with an interactive command palette (`:`) and global search (`/`)
21
22
  - 📦 **Package Manager Friendly** - Works with npm, yarn, and pnpm
22
23
  - 👥 **Team Ready** - Shared configurations and enterprise deployment
23
24
 
@@ -44,6 +45,8 @@ coco -i
44
45
  - **`coco changelog`** - Create changelogs from commit history
45
46
  - **`coco recap`** - Summarize recent changes and activity
46
47
  - **`coco review`** - AI-powered code review of your changes
48
+ - **`coco log`** - Explore commit history with graph, filters, JSON output, and commit details
49
+ - **`coco ui`** - Open the full-screen Git workstation TUI
47
50
  - **`coco init`** - Interactive setup wizard
48
51
 
49
52
  ## Usage Examples
@@ -85,8 +88,32 @@ coco recap --yesterday
85
88
 
86
89
  # Code review before committing
87
90
  coco review
91
+
92
+ # Explore commit history
93
+ coco ui
94
+ coco ui --view status
95
+ coco log --limit 20
96
+ coco log -i
97
+ coco log --view full --limit 20
98
+ coco log --all --limit 20
99
+ coco log --author "Grace Hopper" --path src
100
+ coco log --commit HEAD
101
+ coco log --format json
102
+ ```
103
+
104
+ ### Navigating the TUI
105
+
106
+ `coco ui` and `coco log -i` share a chord-driven navigation model. Press `g` and then a second key to jump anywhere; `<` (or `Esc`) pops the navigation stack back.
107
+
108
+ ```text
109
+ g h history g c compose < back
110
+ g s status g b branches Esc back / close modal
111
+ g d diff g t tags ? help overlay
112
+ g z stash : command palette
88
113
  ```
89
114
 
115
+ The command palette (`:`) is an interactive launcher with fuzzy filter and recently-used at the top — every keybinding and workflow action is reachable from there. `/` searches the active view (history, branches, tags, or stash). See the [Coco UI](https://github.com/gfargo/coco/wiki/Coco-UI) wiki page for the full keymap.
116
+
90
117
  ## Configuration
91
118
 
92
119
  Configure `coco` for your workflow with the interactive setup wizard:
@@ -109,6 +136,11 @@ coco init --scope project
109
136
  {
110
137
  "mode": "interactive",
111
138
  "conventionalCommits": true,
139
+ "logTui": {
140
+ "theme": {
141
+ "preset": "catppuccin"
142
+ }
143
+ },
112
144
  "service": {
113
145
  "provider": "openai",
114
146
  "model": "gpt-4o"
@@ -126,6 +158,8 @@ For comprehensive guides, advanced usage, and detailed configuration options, vi
126
158
  - **[Getting Started](https://github.com/gfargo/coco/wiki/Getting-Started)** - Complete beginner's guide from installation to first commit
127
159
  - **[Command Reference](https://github.com/gfargo/coco/wiki/Command-Reference)** - Detailed command options and examples
128
160
  - **[Configuration Overview](https://github.com/gfargo/coco/wiki/Config-Overview)** - All configuration options and setup methods
161
+ - **[Coco UI](https://github.com/gfargo/coco/wiki/Coco-UI)** - GitKraken-style terminal workstation guide
162
+ - **[Interactive Log TUI](https://github.com/gfargo/coco/wiki/Interactive-Log-TUI)** - History-focused `coco log -i` guide
129
163
  - **[Team Collaboration](https://github.com/gfargo/coco/wiki/Team-Collaboration)** - Enterprise deployment and team adoption strategies
130
164
 
131
165
  **Advanced Resources:**
package/dist/index.d.ts CHANGED
@@ -1,23 +1,49 @@
1
1
  #!/usr/bin/env node
2
2
  import * as yargs from 'yargs';
3
3
  import { Arguments } from 'yargs';
4
- import { OllamaInput, ChatOllama } from '@langchain/ollama';
5
- import { BaseLLMParams } from '@langchain/core/language_models/llms';
6
4
  import * as _langchain_openai from '@langchain/openai';
7
- import { TiktokenModel, OpenAIInput, ChatOpenAI } from '@langchain/openai';
5
+ import { TiktokenModel, ChatOpenAI } from '@langchain/openai';
8
6
  import { SimpleGit } from 'simple-git';
9
7
  import { ChatAnthropic } from '@langchain/anthropic';
8
+ import { ChatOllama } from '@langchain/ollama';
10
9
  import { Color } from 'chalk';
11
10
  import { TiktokenModel as TiktokenModel$1 } from 'tiktoken';
12
11
 
12
+ type LogInkBorderStyle = 'round' | 'single' | 'classic';
13
+ type LogInkThemePreset = 'default' | 'monochrome' | 'catppuccin' | 'gruvbox';
14
+ type LogInkThemeColors = {
15
+ accent?: string;
16
+ border?: string;
17
+ danger?: string;
18
+ focusBorder?: string;
19
+ gitAdded?: string;
20
+ gitDeleted?: string;
21
+ gitModified?: string;
22
+ info?: string;
23
+ muted?: string;
24
+ selection?: string;
25
+ success?: string;
26
+ warning?: string;
27
+ };
28
+ type LogInkThemeConfig = {
29
+ ascii?: boolean;
30
+ borderStyle?: LogInkBorderStyle;
31
+ colors?: LogInkThemeColors;
32
+ preset?: LogInkThemePreset;
33
+ };
34
+
13
35
  type LLMProvider = 'openai' | 'ollama' | 'anthropic';
36
+ type DynamicModelTask = 'summarize' | 'commit' | 'changelog' | 'review' | 'recap' | 'repair' | 'largeDiff';
37
+ type DynamicModelPreference = 'cost' | 'balanced' | 'quality';
14
38
  type OpenAIModel = TiktokenModel | 'gpt-4o-mini' | 'gpt-4o' | 'gpt-4.1' | 'gpt-4.1-mini' | 'gpt-4.1-nano';
15
39
  type AnthropicModel = 'claude-sonnet-4-0' | 'claude-3-7-sonnet-latest' | 'claude-3-5-haiku-latest' | 'claude-3-5-sonnet-latest' | 'claude-3-5-sonnet-20241022' | 'claude-3-5-sonnet-20240620' | 'claude-3-opus-20240229' | 'claude-3-sonnet-20240229' | 'claude-3-haiku-20240307';
16
40
  type OllamaModel = 'deepseek-r1:1.5b' | 'deepseek-r1:8b' | 'deepseek-r1:32b' | 'codegemma:2b' | 'codegemma:7b-code' | 'codegemma' | 'codellama:13b' | 'codellama:34b' | 'codellama:70b' | 'codellama:7b' | 'codellama:instruct' | 'codellama:latest' | 'codellama' | 'gemma:2b' | 'gemma:7b' | 'gemma:latest' | 'gemma' | 'llama2:13b' | 'llama2:70b' | 'llama2:chat' | 'llama2:latest' | 'llama2:text' | 'llama2' | 'llama3:70b-text' | 'llama3:70b' | 'llama3:latest' | 'llama3:text' | 'llama3.1:70b' | 'llama3.1:8b' | 'llama3.1:latest' | 'llama3.2' | 'llama3.2:latest' | 'llama3.2:1b' | 'llama3.2:3b' | 'llama3' | 'llava-llama3:latest' | 'dolphin-llama3:latest' | 'dolphin-llama3:8b' | 'dolphin-llama3:70b' | 'mistral:7b' | 'mistral:latest' | 'mistral:text' | 'mistral' | 'phi3:14b' | 'phi3:3.8b' | 'phi3:instruct' | 'phi3:medium-128k' | 'phi3:medium-4k' | 'phi3:medium' | 'phi3' | 'qwen2:0.5b' | 'qwen2:1.5b' | 'qwen2:72b-text' | 'qwen2:72b' | 'qwen2' | 'qwen2.5-coder:latest' | 'qwen2.5-coder:0.5b' | 'qwen2.5-coder:1.5b' | 'qwen2.5-coder:3b' | 'qwen2.5-coder:7b' | 'qwen2.5-coder:14b' | 'qwen2.5-coder:32b';
17
41
  type LLMModel = OpenAIModel | OllamaModel | AnthropicModel;
42
+ type ConfiguredLLMModel = LLMModel | 'dynamic';
43
+ type DynamicModelProfile = Partial<Record<DynamicModelTask, LLMModel>>;
18
44
  type BaseLLMService = {
19
45
  provider: LLMProvider;
20
- model: LLMModel;
46
+ model: ConfiguredLLMModel;
21
47
  /**
22
48
  * The maximum number of tokens per request.
23
49
  *
@@ -63,6 +89,16 @@ type BaseLLMService = {
63
89
  * @default 3
64
90
  */
65
91
  maxParsingAttempts?: number;
92
+ /**
93
+ * Optional task-to-model overrides used when model is set to "dynamic".
94
+ */
95
+ dynamicModels?: DynamicModelProfile;
96
+ /**
97
+ * Default dynamic routing preference when model is set to "dynamic".
98
+ *
99
+ * @default 'balanced'
100
+ */
101
+ dynamicModelPreference?: DynamicModelPreference;
66
102
  };
67
103
  type Authentication = {
68
104
  type: 'None';
@@ -80,11 +116,16 @@ type Authentication = {
80
116
  apiKey: string;
81
117
  };
82
118
  };
83
- type OpenAIFields = Partial<OpenAIInput> & BaseLLMParams;
84
- type OllamaFields = Partial<OllamaInput> & BaseLLMParams;
119
+ /**
120
+ * Provider-specific extra options forwarded to the underlying LangChain client.
121
+ * Decoupled from upstream input types so schema generation stays stable across
122
+ * langchain releases.
123
+ */
124
+ type OpenAIFields = Record<string, unknown>;
125
+ type OllamaFields = Record<string, unknown>;
85
126
  type OpenAILLMService = BaseLLMService & {
86
127
  provider: 'openai';
87
- model: OpenAIModel;
128
+ model: OpenAIModel | 'dynamic';
88
129
  /**
89
130
  * Custom base URL for OpenAI-compatible APIs (e.g., OpenRouter, Azure OpenAI).
90
131
  * If not specified, uses the default OpenAI API endpoint.
@@ -97,13 +138,13 @@ type OpenAILLMService = BaseLLMService & {
97
138
  };
98
139
  type OllamaLLMService = BaseLLMService & {
99
140
  provider: 'ollama';
100
- model: OllamaModel;
141
+ model: OllamaModel | 'dynamic';
101
142
  endpoint: string;
102
143
  fields?: OllamaFields;
103
144
  };
104
145
  type AnthropicLLMService = BaseLLMService & {
105
146
  provider: 'anthropic';
106
- model: AnthropicModel;
147
+ model: AnthropicModel | 'dynamic';
107
148
  fields?: {
108
149
  temperature?: number;
109
150
  maxTokens?: number;
@@ -189,6 +230,15 @@ type BaseConfig = {
189
230
  * @example { "model": "o4-mini", "approval-mode": "auto-edit" }
190
231
  */
191
232
  autoFixToolOptions?: Record<string, string>;
233
+ /**
234
+ * Interactive log TUI settings.
235
+ */
236
+ logTui?: {
237
+ /**
238
+ * Theme settings for `coco log -i`.
239
+ */
240
+ theme?: LogInkThemeConfig;
241
+ };
192
242
  };
193
243
  type ConfigWithServiceObject = BaseConfig & Partial<BaseCommandOptions> & {
194
244
  service: LLMService;
@@ -216,7 +266,7 @@ interface ChangelogOptions extends BaseCommandOptions {
216
266
  }
217
267
  type ChangelogArgv = Arguments<ChangelogOptions>;
218
268
 
219
- declare const _default$3: {
269
+ declare const _default$5: {
220
270
  command: string;
221
271
  desc: string;
222
272
  builder: (yargs: yargs.Argv) => yargs.Argv<yargs.Omit<{}, string> & yargs.InferredOptionTypes<Record<string, yargs.Options>>>;
@@ -233,10 +283,13 @@ interface CommitOptions extends BaseCommandOptions {
233
283
  conventional: boolean;
234
284
  includeBranchName: boolean;
235
285
  noVerify: boolean;
286
+ split?: boolean;
287
+ plan?: boolean;
288
+ apply?: boolean;
236
289
  }
237
290
  type CommitArgv = Arguments<CommitOptions>;
238
291
 
239
- declare const _default$2: {
292
+ declare const _default$4: {
240
293
  command: string;
241
294
  desc: string;
242
295
  builder: (yargs: yargs.Argv) => yargs.Argv<yargs.Omit<{}, string> & yargs.InferredOptionTypes<Record<string, yargs.Options>>>;
@@ -246,13 +299,14 @@ declare const _default$2: {
246
299
 
247
300
  type InstallationScope = 'global' | 'project';
248
301
 
249
- declare const _default$1: {
302
+ declare const _default$3: {
250
303
  command: string;
251
304
  desc: string;
252
305
  builder: (yargs: yargs.Argv) => yargs.Argv<yargs.Omit<{}, string> & yargs.InferredOptionTypes<Record<string, yargs.Options>>>;
253
306
  handler: (argv: {
254
307
  [x: string]: unknown;
255
308
  scope?: InstallationScope | undefined;
309
+ dryRun?: boolean | undefined;
256
310
  interactive: boolean;
257
311
  verbose: boolean;
258
312
  version: boolean;
@@ -262,6 +316,7 @@ declare const _default$1: {
262
316
  } | Promise<{
263
317
  [x: string]: unknown;
264
318
  scope?: InstallationScope | undefined;
319
+ dryRun?: boolean | undefined;
265
320
  interactive: boolean;
266
321
  verbose: boolean;
267
322
  version: boolean;
@@ -272,6 +327,32 @@ declare const _default$1: {
272
327
  options: Record<string, yargs.Options>;
273
328
  };
274
329
 
330
+ type LogFormat = 'table' | 'json';
331
+ type LogView = 'compact' | 'graph' | 'full';
332
+ interface LogOptions extends BaseCommandOptions {
333
+ all?: boolean;
334
+ author?: string;
335
+ branch?: string;
336
+ commit?: string;
337
+ format?: LogFormat;
338
+ limit?: number;
339
+ merges?: boolean;
340
+ noMerges?: boolean;
341
+ path?: string | string[];
342
+ since?: string;
343
+ until?: string;
344
+ view?: LogView;
345
+ }
346
+ type LogArgv = Arguments<LogOptions>;
347
+
348
+ declare const _default$2: {
349
+ command: string;
350
+ desc: string;
351
+ builder: (yargs: yargs.Argv) => yargs.Argv<yargs.Omit<{}, string> & yargs.InferredOptionTypes<Record<string, yargs.Options>>>;
352
+ handler: (argv: LogArgv) => Promise<void>;
353
+ options: Record<string, yargs.Options>;
354
+ };
355
+
275
356
  interface RecapOptions extends BaseCommandOptions {
276
357
  yesterday?: boolean;
277
358
  'last-week'?: boolean;
@@ -282,7 +363,7 @@ interface RecapOptions extends BaseCommandOptions {
282
363
  }
283
364
  type RecapArgv = Arguments<RecapOptions>;
284
365
 
285
- declare const _default: {
366
+ declare const _default$1: {
286
367
  command: string;
287
368
  desc: string;
288
369
  builder: (yargs: yargs.Argv) => yargs.Argv<yargs.Omit<{}, string> & yargs.InferredOptionTypes<Record<string, yargs.Options>>>;
@@ -290,6 +371,25 @@ declare const _default: {
290
371
  options: Record<string, yargs.Options>;
291
372
  };
292
373
 
374
+ type UiView = 'history' | 'status' | 'diff';
375
+ interface UiOptions extends BaseCommandOptions {
376
+ all?: boolean;
377
+ branch?: string;
378
+ limit?: number;
379
+ path?: string | string[];
380
+ theme?: LogInkThemePreset;
381
+ view?: UiView;
382
+ }
383
+ type UiArgv = Arguments<UiOptions>;
384
+
385
+ declare const _default: {
386
+ command: string;
387
+ desc: string;
388
+ builder: (yargs: yargs.Argv) => yargs.Argv<yargs.Omit<{}, string> & yargs.InferredOptionTypes<Record<string, yargs.Options>>>;
389
+ handler: (argv: UiArgv) => Promise<void>;
390
+ options: Record<string, yargs.Options>;
391
+ };
392
+
293
393
  /**
294
394
  * Creates and configures an LLM instance based on the provider and configuration.
295
395
  *
@@ -336,6 +436,20 @@ type TokenCounter = Awaited<ReturnType<typeof getTokenCounter>>;
336
436
  */
337
437
  declare const getTokenCounter: (modelName: TiktokenModel$1) => Promise<(text: string) => number>;
338
438
 
439
+ type LlmCallMetadata = {
440
+ task: string;
441
+ command?: string;
442
+ provider?: string;
443
+ model?: string;
444
+ retryAttempt?: number;
445
+ parserType?: string;
446
+ variableKeys?: string[];
447
+ promptTokens?: number;
448
+ elapsedMs?: number;
449
+ inputDocuments?: number;
450
+ inputChunks?: number;
451
+ };
452
+
339
453
  type FileChangeStatus = 'modified' | 'renamed' | 'added' | 'deleted' | 'untracked' | 'unknown';
340
454
  interface FileChange {
341
455
  summary: string;
@@ -389,6 +503,7 @@ interface BaseParserOptions {
389
503
  * @default 6
390
504
  */
391
505
  maxConcurrent?: number;
506
+ metadata?: Partial<LlmCallMetadata>;
392
507
  }
393
508
  interface BaseParserInput {
394
509
  options: BaseParserOptions;
@@ -424,5 +539,5 @@ declare namespace types_d {
424
539
  export type { types_d_BaseParserInput as BaseParserInput, types_d_BaseParserOptions as BaseParserOptions, types_d_CommandHandler as CommandHandler, types_d_CommitLogParserInput as CommitLogParserInput, types_d_ConfirmMessage as ConfirmMessage, types_d_ConfirmMessageCallback as ConfirmMessageCallback, types_d_DiffNode as DiffNode, types_d_DirectoryDiff as DirectoryDiff, types_d_FileChange as FileChange, types_d_FileChangeParserInput as FileChangeParserInput, types_d_FileChangeStatus as FileChangeStatus, types_d_FileDiff as FileDiff, types_d_GetChangesResult as GetChangesResult };
425
540
  }
426
541
 
427
- export { _default$3 as changelog, _default$2 as commit, _default$1 as init, _default as recap, types_d as types };
542
+ export { _default$5 as changelog, _default$4 as commit, _default$3 as init, _default$2 as log, _default$1 as recap, types_d as types, _default as ui };
428
543
  export type { Config$1 as Config };