git-coco 0.13.0 → 0.13.2
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/LICENSE +1 -1
- package/README.md +42 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.esm.mjs +45 -50
- package/dist/index.js +44 -49
- package/package.json +1 -1
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
- **`changelog`**: create changelogs for the current branch or a range of commits.
|
|
16
16
|
|
|
17
|
+
- **`recap`**: summarize changes from working-tree, or yesterday, or in the last month, or since the last tag!
|
|
18
|
+
|
|
17
19
|
- **`init`**: step by step wizard to set up `coco` globally or for a project.
|
|
18
20
|
|
|
19
21
|
## Getting Started
|
|
@@ -42,6 +44,24 @@ coco
|
|
|
42
44
|
coco commit
|
|
43
45
|
```
|
|
44
46
|
|
|
47
|
+
#### Useful options
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# --append
|
|
52
|
+
# Add content to the end of the generated commit
|
|
53
|
+
coco --append "Resolves #128"
|
|
54
|
+
|
|
55
|
+
# --append-ticket
|
|
56
|
+
# Automatically append Jira/Linear ticket ID from the branch name to the commit message
|
|
57
|
+
coco --append-ticket
|
|
58
|
+
|
|
59
|
+
# --additional
|
|
60
|
+
# Add extra context before generating the commit
|
|
61
|
+
coco --additional "Resolves UX bug with sign up button"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
|
|
45
65
|
### **`coco changelog`**
|
|
46
66
|
|
|
47
67
|
Creates changelogs.
|
|
@@ -52,8 +72,22 @@ coco changelog
|
|
|
52
72
|
|
|
53
73
|
# For a specific range
|
|
54
74
|
coco changelog -r HEAD~5:HEAD
|
|
75
|
+
|
|
76
|
+
# For a target branch
|
|
77
|
+
coco changelog -b other-branch
|
|
55
78
|
```
|
|
56
79
|
|
|
80
|
+
### **`coco recap`**
|
|
81
|
+
|
|
82
|
+
Summarize the working-tree, or other configured ranges
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Summarize all working directory changes
|
|
86
|
+
coco recap
|
|
87
|
+
|
|
88
|
+
# Or these available ranges
|
|
89
|
+
coco recap --yesterday | --last-week | --last-month | --last-tag
|
|
90
|
+
```
|
|
57
91
|
|
|
58
92
|
### Stdout vs. Interactive Mode
|
|
59
93
|
|
|
@@ -87,3 +121,11 @@ You can specify files to be ignored when generating commit messages by adding th
|
|
|
87
121
|
## Contribution
|
|
88
122
|
|
|
89
123
|
We welcome contributions! Check out our [CONTRIBUTING.md](CONTRIBUTING.md) for more information.
|
|
124
|
+
|
|
125
|
+
## Project Stats
|
|
126
|
+
|
|
127
|
+

|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
MIT © [gfargo](https://github.com/gfargo/)
|
package/dist/index.d.ts
CHANGED
|
@@ -195,9 +195,9 @@ declare const _default$1: {
|
|
|
195
195
|
|
|
196
196
|
interface RecapOptions extends BaseCommandOptions {
|
|
197
197
|
yesterday?: boolean;
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
198
|
+
'last-week'?: boolean;
|
|
199
|
+
'last-month'?: boolean;
|
|
200
|
+
'last-tag'?: boolean;
|
|
201
201
|
}
|
|
202
202
|
type RecapArgv = Arguments<RecapOptions>;
|
|
203
203
|
|
package/dist/index.esm.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { ConditionalPromptSelector, isChatModel } from '@langchain/core/example_
|
|
|
4
4
|
import yargs from 'yargs';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
6
|
import * as fs from 'fs';
|
|
7
|
-
import fs__default from 'fs';
|
|
7
|
+
import fs__default, { promises } from 'fs';
|
|
8
8
|
import { confirm, editor, select, password, input } from '@inquirer/prompts';
|
|
9
9
|
import * as ini from 'ini';
|
|
10
10
|
import * as os from 'os';
|
|
@@ -55,7 +55,7 @@ const getCommandUsageHeader = (command) => {
|
|
|
55
55
|
return chalk.green(`${USAGE_BANNER}\n${chalk.white('Command:')}\n\xa0\xa0\xa0\xa0\xa0 $0 ${chalk.greenBright(command)} [options]`);
|
|
56
56
|
};
|
|
57
57
|
const CONFIG_ALREADY_EXISTS = (path) => {
|
|
58
|
-
return `
|
|
58
|
+
return `existing config found in '${path}', do you want to override it?`;
|
|
59
59
|
};
|
|
60
60
|
|
|
61
61
|
/**
|
|
@@ -376,11 +376,11 @@ function loadGitConfig(config) {
|
|
|
376
376
|
if (fs.existsSync(gitConfigPath)) {
|
|
377
377
|
const gitConfigRaw = fs.readFileSync(gitConfigPath, 'utf-8');
|
|
378
378
|
const gitConfigParsed = ini.parse(gitConfigRaw);
|
|
379
|
-
const
|
|
379
|
+
const gitConfigServiceObject = gitConfigParsed.coco?.service;
|
|
380
380
|
let service = config.service;
|
|
381
|
-
if (
|
|
382
|
-
const gitServiceConfig =
|
|
383
|
-
service =
|
|
381
|
+
if (gitConfigServiceObject) {
|
|
382
|
+
const gitServiceConfig = JSON.parse(gitConfigServiceObject);
|
|
383
|
+
service = gitServiceConfig || config?.service;
|
|
384
384
|
}
|
|
385
385
|
config = {
|
|
386
386
|
...config,
|
|
@@ -391,32 +391,11 @@ function loadGitConfig(config) {
|
|
|
391
391
|
ignoredFiles: gitConfigParsed.coco?.ignoredFiles || config.ignoredFiles,
|
|
392
392
|
ignoredExtensions: gitConfigParsed.coco?.ignoredExtensions || config.ignoredExtensions,
|
|
393
393
|
defaultBranch: gitConfigParsed.coco?.defaultBranch || config.defaultBranch,
|
|
394
|
+
verbose: gitConfigParsed.coco?.verbose || config.verbose,
|
|
394
395
|
};
|
|
395
396
|
}
|
|
396
397
|
return removeUndefined(config);
|
|
397
398
|
}
|
|
398
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
399
|
-
function parseServiceConfig$1(service) {
|
|
400
|
-
if (!service)
|
|
401
|
-
return undefined;
|
|
402
|
-
switch (service.provider) {
|
|
403
|
-
case 'openai':
|
|
404
|
-
return {
|
|
405
|
-
provider: 'openai',
|
|
406
|
-
model: service.model,
|
|
407
|
-
fields: { apiKey: service.apiKey },
|
|
408
|
-
};
|
|
409
|
-
case 'ollama':
|
|
410
|
-
return {
|
|
411
|
-
provider: 'ollama',
|
|
412
|
-
model: service.model,
|
|
413
|
-
endpoint: service.endpoint,
|
|
414
|
-
fields: service.fields,
|
|
415
|
-
};
|
|
416
|
-
default:
|
|
417
|
-
return undefined;
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
399
|
/**
|
|
421
400
|
* Appends the provided configuration to a git config file.
|
|
422
401
|
*
|
|
@@ -431,15 +410,18 @@ const appendToGitConfig = async (filePath, config) => {
|
|
|
431
410
|
const getNewContent = async () => {
|
|
432
411
|
const contentLines = [header];
|
|
433
412
|
for (const key in config) {
|
|
434
|
-
|
|
435
|
-
if (typeof
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
413
|
+
const value = config[key];
|
|
414
|
+
if (typeof value === 'object') {
|
|
415
|
+
// Serialize object to JSON string
|
|
416
|
+
contentLines.push(`\t${key} = ${JSON.stringify(value)}`);
|
|
417
|
+
}
|
|
418
|
+
else if (typeof value === 'string' && value.includes('\n')) {
|
|
419
|
+
// Wrap strings with new lines in quotes
|
|
420
|
+
contentLines.push(`\t${key} = ${JSON.stringify(value)}`);
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
contentLines.push(`\t${key} = ${value}`);
|
|
441
424
|
}
|
|
442
|
-
contentLines.push(`\t${key} = ${config[key]}`);
|
|
443
425
|
}
|
|
444
426
|
return contentLines.join('\n');
|
|
445
427
|
};
|
|
@@ -2475,8 +2457,8 @@ const options$3 = {
|
|
|
2475
2457
|
description: 'Toggle interactive mode',
|
|
2476
2458
|
},
|
|
2477
2459
|
};
|
|
2478
|
-
const builder$3 = (
|
|
2479
|
-
return
|
|
2460
|
+
const builder$3 = (yargs) => {
|
|
2461
|
+
return yargs.options(options$3).usage(getCommandUsageHeader(changelog.command));
|
|
2480
2462
|
};
|
|
2481
2463
|
|
|
2482
2464
|
var changelog = {
|
|
@@ -5966,8 +5948,14 @@ async function parseDefaultFileDiff(nodeFile, commit = '--staged', git) {
|
|
|
5966
5948
|
return await git.diff([nodeFile.filePath]);
|
|
5967
5949
|
}
|
|
5968
5950
|
else if (commit === '--untracked') {
|
|
5969
|
-
// For untracked files,
|
|
5970
|
-
|
|
5951
|
+
// For untracked files, read the file content directly from the filesystem
|
|
5952
|
+
try {
|
|
5953
|
+
const fileContent = await promises.readFile(nodeFile.filePath, 'utf-8');
|
|
5954
|
+
return fileContent;
|
|
5955
|
+
}
|
|
5956
|
+
catch (error) {
|
|
5957
|
+
throw new Error(`Error reading untracked file: ${error?.message || 'Unknown error'}`);
|
|
5958
|
+
}
|
|
5971
5959
|
}
|
|
5972
5960
|
return await git.diff([commit, nodeFile.filePath]);
|
|
5973
5961
|
}
|
|
@@ -6380,8 +6368,8 @@ const options$2 = {
|
|
|
6380
6368
|
type: 'string',
|
|
6381
6369
|
},
|
|
6382
6370
|
};
|
|
6383
|
-
const builder$2 = (
|
|
6384
|
-
return
|
|
6371
|
+
const builder$2 = (yargs) => {
|
|
6372
|
+
return yargs.options(options$2).usage(getCommandUsageHeader(commit.command));
|
|
6385
6373
|
};
|
|
6386
6374
|
|
|
6387
6375
|
var commit = {
|
|
@@ -6480,9 +6468,16 @@ async function checkAndHandlePackageInstallation({ global = false, logger, }) {
|
|
|
6480
6468
|
try {
|
|
6481
6469
|
// Global installation
|
|
6482
6470
|
if (global) {
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6471
|
+
const shouldInstall = await confirm({
|
|
6472
|
+
message: `Would you like to install/update '${packageName}' globally at this time?`,
|
|
6473
|
+
default: true,
|
|
6474
|
+
});
|
|
6475
|
+
if (!shouldInstall) {
|
|
6476
|
+
return;
|
|
6477
|
+
}
|
|
6478
|
+
logger.startSpinner(`Updating '${packageName}'...`, { color: 'blue' });
|
|
6479
|
+
// await installNpmPackage({ name: packageName, flags: ['-g'] })
|
|
6480
|
+
logger.stopSpinner(`Updated '${packageName}'`);
|
|
6486
6481
|
return;
|
|
6487
6482
|
}
|
|
6488
6483
|
// Project level installation
|
|
@@ -6995,17 +6990,17 @@ const options = {
|
|
|
6995
6990
|
type: 'boolean',
|
|
6996
6991
|
description: 'Recap for yesterday',
|
|
6997
6992
|
},
|
|
6998
|
-
|
|
6993
|
+
'last-week': {
|
|
6999
6994
|
alias: 'week',
|
|
7000
6995
|
type: 'boolean',
|
|
7001
6996
|
description: 'Recap for last week',
|
|
7002
6997
|
},
|
|
7003
|
-
|
|
6998
|
+
'last-month': {
|
|
7004
6999
|
alias: 'month',
|
|
7005
7000
|
type: 'boolean',
|
|
7006
7001
|
description: 'Recap for last month',
|
|
7007
7002
|
},
|
|
7008
|
-
|
|
7003
|
+
'last-tag': {
|
|
7009
7004
|
alias: 'tag',
|
|
7010
7005
|
type: 'boolean',
|
|
7011
7006
|
description: 'Recap for last tag',
|
|
@@ -7016,8 +7011,8 @@ const options = {
|
|
|
7016
7011
|
description: 'Toggle interactive mode',
|
|
7017
7012
|
},
|
|
7018
7013
|
};
|
|
7019
|
-
const builder = (
|
|
7020
|
-
return
|
|
7014
|
+
const builder = (yargs) => {
|
|
7015
|
+
return yargs.options(options).usage(getCommandUsageHeader(recap.command));
|
|
7021
7016
|
};
|
|
7022
7017
|
|
|
7023
7018
|
var recap = {
|
package/dist/index.js
CHANGED
|
@@ -76,7 +76,7 @@ const getCommandUsageHeader = (command) => {
|
|
|
76
76
|
return chalk.green(`${USAGE_BANNER}\n${chalk.white('Command:')}\n\xa0\xa0\xa0\xa0\xa0 $0 ${chalk.greenBright(command)} [options]`);
|
|
77
77
|
};
|
|
78
78
|
const CONFIG_ALREADY_EXISTS = (path) => {
|
|
79
|
-
return `
|
|
79
|
+
return `existing config found in '${path}', do you want to override it?`;
|
|
80
80
|
};
|
|
81
81
|
|
|
82
82
|
/**
|
|
@@ -397,11 +397,11 @@ function loadGitConfig(config) {
|
|
|
397
397
|
if (fs__namespace.existsSync(gitConfigPath)) {
|
|
398
398
|
const gitConfigRaw = fs__namespace.readFileSync(gitConfigPath, 'utf-8');
|
|
399
399
|
const gitConfigParsed = ini__namespace.parse(gitConfigRaw);
|
|
400
|
-
const
|
|
400
|
+
const gitConfigServiceObject = gitConfigParsed.coco?.service;
|
|
401
401
|
let service = config.service;
|
|
402
|
-
if (
|
|
403
|
-
const gitServiceConfig =
|
|
404
|
-
service =
|
|
402
|
+
if (gitConfigServiceObject) {
|
|
403
|
+
const gitServiceConfig = JSON.parse(gitConfigServiceObject);
|
|
404
|
+
service = gitServiceConfig || config?.service;
|
|
405
405
|
}
|
|
406
406
|
config = {
|
|
407
407
|
...config,
|
|
@@ -412,32 +412,11 @@ function loadGitConfig(config) {
|
|
|
412
412
|
ignoredFiles: gitConfigParsed.coco?.ignoredFiles || config.ignoredFiles,
|
|
413
413
|
ignoredExtensions: gitConfigParsed.coco?.ignoredExtensions || config.ignoredExtensions,
|
|
414
414
|
defaultBranch: gitConfigParsed.coco?.defaultBranch || config.defaultBranch,
|
|
415
|
+
verbose: gitConfigParsed.coco?.verbose || config.verbose,
|
|
415
416
|
};
|
|
416
417
|
}
|
|
417
418
|
return removeUndefined(config);
|
|
418
419
|
}
|
|
419
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
420
|
-
function parseServiceConfig$1(service) {
|
|
421
|
-
if (!service)
|
|
422
|
-
return undefined;
|
|
423
|
-
switch (service.provider) {
|
|
424
|
-
case 'openai':
|
|
425
|
-
return {
|
|
426
|
-
provider: 'openai',
|
|
427
|
-
model: service.model,
|
|
428
|
-
fields: { apiKey: service.apiKey },
|
|
429
|
-
};
|
|
430
|
-
case 'ollama':
|
|
431
|
-
return {
|
|
432
|
-
provider: 'ollama',
|
|
433
|
-
model: service.model,
|
|
434
|
-
endpoint: service.endpoint,
|
|
435
|
-
fields: service.fields,
|
|
436
|
-
};
|
|
437
|
-
default:
|
|
438
|
-
return undefined;
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
420
|
/**
|
|
442
421
|
* Appends the provided configuration to a git config file.
|
|
443
422
|
*
|
|
@@ -452,15 +431,18 @@ const appendToGitConfig = async (filePath, config) => {
|
|
|
452
431
|
const getNewContent = async () => {
|
|
453
432
|
const contentLines = [header];
|
|
454
433
|
for (const key in config) {
|
|
455
|
-
|
|
456
|
-
if (typeof
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
434
|
+
const value = config[key];
|
|
435
|
+
if (typeof value === 'object') {
|
|
436
|
+
// Serialize object to JSON string
|
|
437
|
+
contentLines.push(`\t${key} = ${JSON.stringify(value)}`);
|
|
438
|
+
}
|
|
439
|
+
else if (typeof value === 'string' && value.includes('\n')) {
|
|
440
|
+
// Wrap strings with new lines in quotes
|
|
441
|
+
contentLines.push(`\t${key} = ${JSON.stringify(value)}`);
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
contentLines.push(`\t${key} = ${value}`);
|
|
462
445
|
}
|
|
463
|
-
contentLines.push(`\t${key} = ${config[key]}`);
|
|
464
446
|
}
|
|
465
447
|
return contentLines.join('\n');
|
|
466
448
|
};
|
|
@@ -2496,8 +2478,8 @@ const options$3 = {
|
|
|
2496
2478
|
description: 'Toggle interactive mode',
|
|
2497
2479
|
},
|
|
2498
2480
|
};
|
|
2499
|
-
const builder$3 = (
|
|
2500
|
-
return
|
|
2481
|
+
const builder$3 = (yargs) => {
|
|
2482
|
+
return yargs.options(options$3).usage(getCommandUsageHeader(changelog.command));
|
|
2501
2483
|
};
|
|
2502
2484
|
|
|
2503
2485
|
var changelog = {
|
|
@@ -5987,8 +5969,14 @@ async function parseDefaultFileDiff(nodeFile, commit = '--staged', git) {
|
|
|
5987
5969
|
return await git.diff([nodeFile.filePath]);
|
|
5988
5970
|
}
|
|
5989
5971
|
else if (commit === '--untracked') {
|
|
5990
|
-
// For untracked files,
|
|
5991
|
-
|
|
5972
|
+
// For untracked files, read the file content directly from the filesystem
|
|
5973
|
+
try {
|
|
5974
|
+
const fileContent = await fs.promises.readFile(nodeFile.filePath, 'utf-8');
|
|
5975
|
+
return fileContent;
|
|
5976
|
+
}
|
|
5977
|
+
catch (error) {
|
|
5978
|
+
throw new Error(`Error reading untracked file: ${error?.message || 'Unknown error'}`);
|
|
5979
|
+
}
|
|
5992
5980
|
}
|
|
5993
5981
|
return await git.diff([commit, nodeFile.filePath]);
|
|
5994
5982
|
}
|
|
@@ -6401,8 +6389,8 @@ const options$2 = {
|
|
|
6401
6389
|
type: 'string',
|
|
6402
6390
|
},
|
|
6403
6391
|
};
|
|
6404
|
-
const builder$2 = (
|
|
6405
|
-
return
|
|
6392
|
+
const builder$2 = (yargs) => {
|
|
6393
|
+
return yargs.options(options$2).usage(getCommandUsageHeader(commit.command));
|
|
6406
6394
|
};
|
|
6407
6395
|
|
|
6408
6396
|
var commit = {
|
|
@@ -6501,9 +6489,16 @@ async function checkAndHandlePackageInstallation({ global = false, logger, }) {
|
|
|
6501
6489
|
try {
|
|
6502
6490
|
// Global installation
|
|
6503
6491
|
if (global) {
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6492
|
+
const shouldInstall = await prompts.confirm({
|
|
6493
|
+
message: `Would you like to install/update '${packageName}' globally at this time?`,
|
|
6494
|
+
default: true,
|
|
6495
|
+
});
|
|
6496
|
+
if (!shouldInstall) {
|
|
6497
|
+
return;
|
|
6498
|
+
}
|
|
6499
|
+
logger.startSpinner(`Updating '${packageName}'...`, { color: 'blue' });
|
|
6500
|
+
// await installNpmPackage({ name: packageName, flags: ['-g'] })
|
|
6501
|
+
logger.stopSpinner(`Updated '${packageName}'`);
|
|
6507
6502
|
return;
|
|
6508
6503
|
}
|
|
6509
6504
|
// Project level installation
|
|
@@ -7016,17 +7011,17 @@ const options = {
|
|
|
7016
7011
|
type: 'boolean',
|
|
7017
7012
|
description: 'Recap for yesterday',
|
|
7018
7013
|
},
|
|
7019
|
-
|
|
7014
|
+
'last-week': {
|
|
7020
7015
|
alias: 'week',
|
|
7021
7016
|
type: 'boolean',
|
|
7022
7017
|
description: 'Recap for last week',
|
|
7023
7018
|
},
|
|
7024
|
-
|
|
7019
|
+
'last-month': {
|
|
7025
7020
|
alias: 'month',
|
|
7026
7021
|
type: 'boolean',
|
|
7027
7022
|
description: 'Recap for last month',
|
|
7028
7023
|
},
|
|
7029
|
-
|
|
7024
|
+
'last-tag': {
|
|
7030
7025
|
alias: 'tag',
|
|
7031
7026
|
type: 'boolean',
|
|
7032
7027
|
description: 'Recap for last tag',
|
|
@@ -7037,8 +7032,8 @@ const options = {
|
|
|
7037
7032
|
description: 'Toggle interactive mode',
|
|
7038
7033
|
},
|
|
7039
7034
|
};
|
|
7040
|
-
const builder = (
|
|
7041
|
-
return
|
|
7035
|
+
const builder = (yargs) => {
|
|
7036
|
+
return yargs.options(options).usage(getCommandUsageHeader(recap.command));
|
|
7042
7037
|
};
|
|
7043
7038
|
|
|
7044
7039
|
var recap = {
|