claude-gh-ticket-gen 1.0.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/LICENSE +21 -0
- package/README.md +406 -0
- package/bin/claude-ticket-gen.js +6 -0
- package/dist/cli/commands/config.d.ts +8 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +84 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +9 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +243 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/commands/init.d.ts +8 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +160 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/index.d.ts +6 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +54 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/ui.d.ts +38 -0
- package/dist/cli/ui.d.ts.map +1 -0
- package/dist/cli/ui.js +148 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/core/config-manager.d.ts +48 -0
- package/dist/core/config-manager.d.ts.map +1 -0
- package/dist/core/config-manager.js +165 -0
- package/dist/core/config-manager.js.map +1 -0
- package/dist/core/duplicate-detector.d.ts +13 -0
- package/dist/core/duplicate-detector.d.ts.map +1 -0
- package/dist/core/duplicate-detector.js +123 -0
- package/dist/core/duplicate-detector.js.map +1 -0
- package/dist/core/github.d.ts +46 -0
- package/dist/core/github.d.ts.map +1 -0
- package/dist/core/github.js +187 -0
- package/dist/core/github.js.map +1 -0
- package/dist/core/parser.d.ts +17 -0
- package/dist/core/parser.d.ts.map +1 -0
- package/dist/core/parser.js +177 -0
- package/dist/core/parser.js.map +1 -0
- package/dist/core/types.d.ts +89 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +28 -0
- package/dist/core/types.js.map +1 -0
- package/dist/templates/issue-template.d.ts +17 -0
- package/dist/templates/issue-template.d.ts.map +1 -0
- package/dist/templates/issue-template.js +87 -0
- package/dist/templates/issue-template.js.map +1 -0
- package/dist/templates/parsing-prompt.d.ts +5 -0
- package/dist/templates/parsing-prompt.d.ts.map +1 -0
- package/dist/templates/parsing-prompt.js +70 -0
- package/dist/templates/parsing-prompt.js.map +1 -0
- package/dist/utils/logger.d.ts +69 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +136 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/validators.d.ts +45 -0
- package/dist/utils/validators.d.ts.map +1 -0
- package/dist/utils/validators.js +80 -0
- package/dist/utils/validators.js.map +1 -0
- package/examples/ROADMAP.example.md +84 -0
- package/examples/config.example.json +22 -0
- package/package.json +54 -0
package/dist/cli/ui.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI helpers for CLI (spinners, tables, etc.)
|
|
3
|
+
*/
|
|
4
|
+
import ora from 'ora';
|
|
5
|
+
import Table from 'cli-table3';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import { formatPriority, formatType, truncate } from '../utils/logger.js';
|
|
8
|
+
/**
|
|
9
|
+
* Create and start a spinner
|
|
10
|
+
*/
|
|
11
|
+
export function startSpinner(text) {
|
|
12
|
+
return ora(text).start();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Stop spinner with success
|
|
16
|
+
*/
|
|
17
|
+
export function succeedSpinner(spinner, text) {
|
|
18
|
+
spinner.succeed(text);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Stop spinner with failure
|
|
22
|
+
*/
|
|
23
|
+
export function failSpinner(spinner, text) {
|
|
24
|
+
spinner.fail(text);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Update spinner text
|
|
28
|
+
*/
|
|
29
|
+
export function updateSpinner(spinner, text) {
|
|
30
|
+
spinner.text = text;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Display tasks in a table
|
|
34
|
+
*/
|
|
35
|
+
export function displayTasksTable(tasks) {
|
|
36
|
+
const table = new Table({
|
|
37
|
+
head: [
|
|
38
|
+
chalk.cyan('Priority'),
|
|
39
|
+
chalk.cyan('Type'),
|
|
40
|
+
chalk.cyan('Title'),
|
|
41
|
+
chalk.cyan('Phase'),
|
|
42
|
+
chalk.cyan('Labels'),
|
|
43
|
+
],
|
|
44
|
+
colWidths: [10, 15, 45, 20, 20],
|
|
45
|
+
wordWrap: true,
|
|
46
|
+
});
|
|
47
|
+
tasks.forEach((task) => {
|
|
48
|
+
table.push([
|
|
49
|
+
formatPriority(task.priority),
|
|
50
|
+
formatType(task.type),
|
|
51
|
+
task.isCompleted ? chalk.dim(chalk.strikethrough(task.title)) : task.title,
|
|
52
|
+
task.phase || chalk.dim('N/A'),
|
|
53
|
+
task.labels.join(', ') || chalk.dim('none'),
|
|
54
|
+
]);
|
|
55
|
+
});
|
|
56
|
+
console.log(table.toString());
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Display generation summary
|
|
60
|
+
*/
|
|
61
|
+
export function displaySummary(summary) {
|
|
62
|
+
const table = new Table({
|
|
63
|
+
head: [chalk.cyan('Metric'), chalk.cyan('Count')],
|
|
64
|
+
colWidths: [25, 10],
|
|
65
|
+
});
|
|
66
|
+
table.push(['Total Tasks Parsed', summary.totalTasks.toString()], ['Tasks After Filtering', summary.filteredTasks.toString()], [chalk.green('Issues Created'), chalk.green(summary.created.toString())], [chalk.yellow('Skipped (Completed)'), summary.skipped.toString()], [chalk.blue('Duplicates Detected'), summary.duplicates.toString()], [chalk.red('Errors'), summary.errors.toString()]);
|
|
67
|
+
console.log();
|
|
68
|
+
console.log(chalk.bold('Generation Summary'));
|
|
69
|
+
console.log(table.toString());
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Display configuration in a table
|
|
73
|
+
*/
|
|
74
|
+
export function displayConfig(config) {
|
|
75
|
+
const table = new Table({
|
|
76
|
+
head: [chalk.cyan('Key'), chalk.cyan('Value')],
|
|
77
|
+
colWidths: [35, 45],
|
|
78
|
+
wordWrap: true,
|
|
79
|
+
});
|
|
80
|
+
function addConfigRows(obj, prefix = '') {
|
|
81
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
82
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
83
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
84
|
+
addConfigRows(value, fullKey);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
let displayValue;
|
|
88
|
+
if (value === undefined || value === null) {
|
|
89
|
+
displayValue = chalk.dim('(not set)');
|
|
90
|
+
}
|
|
91
|
+
else if (fullKey.includes('apiKey')) {
|
|
92
|
+
// Mask API key
|
|
93
|
+
displayValue = maskApiKey(String(value));
|
|
94
|
+
}
|
|
95
|
+
else if (typeof value === 'boolean') {
|
|
96
|
+
displayValue = value ? chalk.green('true') : chalk.red('false');
|
|
97
|
+
}
|
|
98
|
+
else if (Array.isArray(value)) {
|
|
99
|
+
displayValue = value.join(', ');
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
displayValue = String(value);
|
|
103
|
+
}
|
|
104
|
+
table.push([fullKey, displayValue]);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
addConfigRows(config);
|
|
109
|
+
console.log(table.toString());
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Mask API key for display
|
|
113
|
+
*/
|
|
114
|
+
function maskApiKey(key) {
|
|
115
|
+
if (key.length <= 20) {
|
|
116
|
+
return '****';
|
|
117
|
+
}
|
|
118
|
+
return key.substring(0, 12) + '...' + key.substring(key.length - 4);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Display a preview of what would be created
|
|
122
|
+
*/
|
|
123
|
+
export function displayPreview(tasks) {
|
|
124
|
+
console.log();
|
|
125
|
+
console.log(chalk.bold.cyan('Preview of Issues to be Created:'));
|
|
126
|
+
console.log(chalk.dim('─'.repeat(80)));
|
|
127
|
+
tasks.forEach((task, index) => {
|
|
128
|
+
console.log();
|
|
129
|
+
console.log(chalk.bold(`${index + 1}. ${task.title}`) +
|
|
130
|
+
' ' +
|
|
131
|
+
formatPriority(task.priority) +
|
|
132
|
+
' ' +
|
|
133
|
+
formatType(task.type));
|
|
134
|
+
if (task.description) {
|
|
135
|
+
console.log(chalk.dim(truncate(task.description, 100)));
|
|
136
|
+
}
|
|
137
|
+
if (task.labels.length > 0) {
|
|
138
|
+
console.log(chalk.blue('Labels: ') + task.labels.join(', '));
|
|
139
|
+
}
|
|
140
|
+
if (task.phase) {
|
|
141
|
+
console.log(chalk.yellow('Phase: ') + task.phase);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
console.log();
|
|
145
|
+
console.log(chalk.dim('─'.repeat(80)));
|
|
146
|
+
console.log(chalk.bold(`Total: ${tasks.length} issues`));
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=ui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/cli/ui.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration management system
|
|
3
|
+
*/
|
|
4
|
+
import { Config } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Get the config directory path
|
|
7
|
+
*/
|
|
8
|
+
export declare function getConfigDir(): string;
|
|
9
|
+
/**
|
|
10
|
+
* Get the config file path
|
|
11
|
+
*/
|
|
12
|
+
export declare function getConfigPath(): string;
|
|
13
|
+
/**
|
|
14
|
+
* Load configuration from file
|
|
15
|
+
*/
|
|
16
|
+
export declare function loadConfig(): Config;
|
|
17
|
+
/**
|
|
18
|
+
* Save configuration to file
|
|
19
|
+
*/
|
|
20
|
+
export declare function saveConfig(config: Config): void;
|
|
21
|
+
/**
|
|
22
|
+
* Get a config value by key path (e.g., "preferences.dryRunByDefault")
|
|
23
|
+
*/
|
|
24
|
+
export declare function getConfigValue(key: string): any;
|
|
25
|
+
/**
|
|
26
|
+
* Set a config value by key path
|
|
27
|
+
*/
|
|
28
|
+
export declare function setConfigValue(key: string, value: any): void;
|
|
29
|
+
/**
|
|
30
|
+
* Reset configuration to defaults
|
|
31
|
+
*/
|
|
32
|
+
export declare function resetConfig(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Check if config file exists
|
|
35
|
+
*/
|
|
36
|
+
export declare function configExists(): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Get all config as an object
|
|
39
|
+
*/
|
|
40
|
+
export declare function getAllConfig(): Config;
|
|
41
|
+
/**
|
|
42
|
+
* Validate that required config is set
|
|
43
|
+
*/
|
|
44
|
+
export declare function validateConfig(): {
|
|
45
|
+
valid: boolean;
|
|
46
|
+
errors: string[];
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=config-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-manager.d.ts","sourceRoot":"","sources":["../../src/core/config-manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAAE,MAAM,EAAkB,MAAM,YAAY,CAAC;AAGpD;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAYD;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CA4BnC;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAU/C;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAc/C;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAuC5D;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAcrE"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration management system
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
5
|
+
import { homedir } from 'os';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
import { DEFAULT_CONFIG } from './types.js';
|
|
8
|
+
import { validateApiKey, validateRepoFormat, validateThreshold } from '../utils/validators.js';
|
|
9
|
+
/**
|
|
10
|
+
* Get the config directory path
|
|
11
|
+
*/
|
|
12
|
+
export function getConfigDir() {
|
|
13
|
+
return join(homedir(), '.config', 'claude-ticket-gen');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get the config file path
|
|
17
|
+
*/
|
|
18
|
+
export function getConfigPath() {
|
|
19
|
+
return join(getConfigDir(), 'config.json');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Ensure config directory exists
|
|
23
|
+
*/
|
|
24
|
+
function ensureConfigDir() {
|
|
25
|
+
const configDir = getConfigDir();
|
|
26
|
+
if (!existsSync(configDir)) {
|
|
27
|
+
mkdirSync(configDir, { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Load configuration from file
|
|
32
|
+
*/
|
|
33
|
+
export function loadConfig() {
|
|
34
|
+
const configPath = getConfigPath();
|
|
35
|
+
if (!existsSync(configPath)) {
|
|
36
|
+
// Return default config if file doesn't exist
|
|
37
|
+
return JSON.parse(JSON.stringify(DEFAULT_CONFIG));
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const content = readFileSync(configPath, 'utf-8');
|
|
41
|
+
const userConfig = JSON.parse(content);
|
|
42
|
+
// Merge with defaults to ensure all properties exist
|
|
43
|
+
return {
|
|
44
|
+
...DEFAULT_CONFIG,
|
|
45
|
+
...userConfig,
|
|
46
|
+
preferences: {
|
|
47
|
+
...DEFAULT_CONFIG.preferences,
|
|
48
|
+
...(userConfig.preferences || {}),
|
|
49
|
+
},
|
|
50
|
+
labelColors: {
|
|
51
|
+
...DEFAULT_CONFIG.labelColors,
|
|
52
|
+
...(userConfig.labelColors || {}),
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
throw new Error(`Failed to load config: ${error.message}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Save configuration to file
|
|
62
|
+
*/
|
|
63
|
+
export function saveConfig(config) {
|
|
64
|
+
ensureConfigDir();
|
|
65
|
+
const configPath = getConfigPath();
|
|
66
|
+
try {
|
|
67
|
+
const content = JSON.stringify(config, null, 2);
|
|
68
|
+
writeFileSync(configPath, content, 'utf-8');
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
throw new Error(`Failed to save config: ${error.message}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get a config value by key path (e.g., "preferences.dryRunByDefault")
|
|
76
|
+
*/
|
|
77
|
+
export function getConfigValue(key) {
|
|
78
|
+
const config = loadConfig();
|
|
79
|
+
const keys = key.split('.');
|
|
80
|
+
let value = config;
|
|
81
|
+
for (const k of keys) {
|
|
82
|
+
if (value && typeof value === 'object' && k in value) {
|
|
83
|
+
value = value[k];
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return value;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Set a config value by key path
|
|
93
|
+
*/
|
|
94
|
+
export function setConfigValue(key, value) {
|
|
95
|
+
const config = loadConfig();
|
|
96
|
+
const keys = key.split('.');
|
|
97
|
+
// Navigate to the parent object
|
|
98
|
+
let current = config;
|
|
99
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
100
|
+
const k = keys[i];
|
|
101
|
+
if (!current[k] || typeof current[k] !== 'object') {
|
|
102
|
+
current[k] = {};
|
|
103
|
+
}
|
|
104
|
+
current = current[k];
|
|
105
|
+
}
|
|
106
|
+
// Set the value
|
|
107
|
+
const lastKey = keys[keys.length - 1];
|
|
108
|
+
// Validate certain keys
|
|
109
|
+
if (key === 'anthropicApiKey' && !validateApiKey(value)) {
|
|
110
|
+
throw new Error('Invalid API key format');
|
|
111
|
+
}
|
|
112
|
+
if (key === 'defaultRepo' && value && !validateRepoFormat(value)) {
|
|
113
|
+
throw new Error('Invalid repository format. Expected: "owner/repo"');
|
|
114
|
+
}
|
|
115
|
+
if (key === 'preferences.duplicateThreshold' && !validateThreshold(value)) {
|
|
116
|
+
throw new Error('Threshold must be a number between 0 and 1');
|
|
117
|
+
}
|
|
118
|
+
// Convert string booleans
|
|
119
|
+
if (value === 'true')
|
|
120
|
+
value = true;
|
|
121
|
+
if (value === 'false')
|
|
122
|
+
value = false;
|
|
123
|
+
// Convert string numbers for threshold
|
|
124
|
+
if (key === 'preferences.duplicateThreshold' && typeof value === 'string') {
|
|
125
|
+
value = parseFloat(value);
|
|
126
|
+
}
|
|
127
|
+
current[lastKey] = value;
|
|
128
|
+
saveConfig(config);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Reset configuration to defaults
|
|
132
|
+
*/
|
|
133
|
+
export function resetConfig() {
|
|
134
|
+
saveConfig(JSON.parse(JSON.stringify(DEFAULT_CONFIG)));
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Check if config file exists
|
|
138
|
+
*/
|
|
139
|
+
export function configExists() {
|
|
140
|
+
return existsSync(getConfigPath());
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Get all config as an object
|
|
144
|
+
*/
|
|
145
|
+
export function getAllConfig() {
|
|
146
|
+
return loadConfig();
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Validate that required config is set
|
|
150
|
+
*/
|
|
151
|
+
export function validateConfig() {
|
|
152
|
+
const config = loadConfig();
|
|
153
|
+
const errors = [];
|
|
154
|
+
if (!config.anthropicApiKey) {
|
|
155
|
+
errors.push('Anthropic API key not set. Use: claude-ticket-gen config set anthropicApiKey <key>');
|
|
156
|
+
}
|
|
157
|
+
else if (!validateApiKey(config.anthropicApiKey)) {
|
|
158
|
+
errors.push('Invalid Anthropic API key format');
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
valid: errors.length === 0,
|
|
162
|
+
errors,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=config-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../src/core/config-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Duplicate issue detection
|
|
3
|
+
*/
|
|
4
|
+
import { ParsedTask, DuplicateCheckResult } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Check if a task is a duplicate of an existing issue
|
|
7
|
+
*/
|
|
8
|
+
export declare function checkDuplicate(task: ParsedTask, repo: string, threshold?: number): Promise<DuplicateCheckResult>;
|
|
9
|
+
/**
|
|
10
|
+
* Check multiple tasks for duplicates
|
|
11
|
+
*/
|
|
12
|
+
export declare function checkDuplicates(tasks: ParsedTask[], repo: string, threshold?: number): Promise<Map<number, DuplicateCheckResult>>;
|
|
13
|
+
//# sourceMappingURL=duplicate-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duplicate-detector.d.ts","sourceRoot":"","sources":["../../src/core/duplicate-detector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAG9D;;GAEG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,MAAY,GACtB,OAAO,CAAC,oBAAoB,CAAC,CAuC/B;AAmFD;;GAEG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,UAAU,EAAE,EACnB,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,MAAY,GACtB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAS5C"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Duplicate issue detection
|
|
3
|
+
*/
|
|
4
|
+
import { searchIssues } from './github.js';
|
|
5
|
+
/**
|
|
6
|
+
* Check if a task is a duplicate of an existing issue
|
|
7
|
+
*/
|
|
8
|
+
export async function checkDuplicate(task, repo, threshold = 0.8) {
|
|
9
|
+
// Search for existing issues
|
|
10
|
+
const existingIssues = await searchIssues(task.title, repo);
|
|
11
|
+
if (existingIssues.length === 0) {
|
|
12
|
+
return { isDuplicate: false };
|
|
13
|
+
}
|
|
14
|
+
// Calculate similarity scores
|
|
15
|
+
let bestMatch = null;
|
|
16
|
+
for (const issue of existingIssues) {
|
|
17
|
+
// Only check open issues
|
|
18
|
+
if (issue.state !== 'open') {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const score = calculateSimilarity(task.title, issue.title);
|
|
22
|
+
if (!bestMatch || score > bestMatch.score) {
|
|
23
|
+
bestMatch = { score, issue };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (!bestMatch) {
|
|
27
|
+
return { isDuplicate: false };
|
|
28
|
+
}
|
|
29
|
+
// Check if similarity exceeds threshold
|
|
30
|
+
if (bestMatch.score >= threshold) {
|
|
31
|
+
return {
|
|
32
|
+
isDuplicate: true,
|
|
33
|
+
existingIssueNumber: bestMatch.issue.number,
|
|
34
|
+
existingIssueTitle: bestMatch.issue.title,
|
|
35
|
+
similarityScore: bestMatch.score,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return { isDuplicate: false };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Calculate similarity between two strings (simple keyword overlap)
|
|
42
|
+
*/
|
|
43
|
+
function calculateSimilarity(str1, str2) {
|
|
44
|
+
const words1 = normalizeAndTokenize(str1);
|
|
45
|
+
const words2 = normalizeAndTokenize(str2);
|
|
46
|
+
if (words1.length === 0 || words2.length === 0) {
|
|
47
|
+
return 0;
|
|
48
|
+
}
|
|
49
|
+
// Calculate Jaccard similarity (intersection / union)
|
|
50
|
+
const set1 = new Set(words1);
|
|
51
|
+
const set2 = new Set(words2);
|
|
52
|
+
const intersection = new Set([...set1].filter((word) => set2.has(word)));
|
|
53
|
+
const union = new Set([...set1, ...set2]);
|
|
54
|
+
return intersection.size / union.size;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Normalize and tokenize a string into keywords
|
|
58
|
+
*/
|
|
59
|
+
function normalizeAndTokenize(str) {
|
|
60
|
+
return (str
|
|
61
|
+
.toLowerCase()
|
|
62
|
+
// Remove special characters
|
|
63
|
+
.replace(/[^\w\s]/g, ' ')
|
|
64
|
+
// Split into words
|
|
65
|
+
.split(/\s+/)
|
|
66
|
+
// Remove common stop words and short words
|
|
67
|
+
.filter((word) => word.length > 2)
|
|
68
|
+
.filter((word) => !STOP_WORDS.has(word)));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Common English stop words to filter out
|
|
72
|
+
*/
|
|
73
|
+
const STOP_WORDS = new Set([
|
|
74
|
+
'the',
|
|
75
|
+
'and',
|
|
76
|
+
'for',
|
|
77
|
+
'are',
|
|
78
|
+
'but',
|
|
79
|
+
'not',
|
|
80
|
+
'you',
|
|
81
|
+
'all',
|
|
82
|
+
'can',
|
|
83
|
+
'her',
|
|
84
|
+
'was',
|
|
85
|
+
'one',
|
|
86
|
+
'our',
|
|
87
|
+
'out',
|
|
88
|
+
'day',
|
|
89
|
+
'get',
|
|
90
|
+
'has',
|
|
91
|
+
'him',
|
|
92
|
+
'his',
|
|
93
|
+
'how',
|
|
94
|
+
'man',
|
|
95
|
+
'new',
|
|
96
|
+
'now',
|
|
97
|
+
'old',
|
|
98
|
+
'see',
|
|
99
|
+
'two',
|
|
100
|
+
'way',
|
|
101
|
+
'who',
|
|
102
|
+
'boy',
|
|
103
|
+
'did',
|
|
104
|
+
'its',
|
|
105
|
+
'let',
|
|
106
|
+
'put',
|
|
107
|
+
'say',
|
|
108
|
+
'she',
|
|
109
|
+
'too',
|
|
110
|
+
'use',
|
|
111
|
+
]);
|
|
112
|
+
/**
|
|
113
|
+
* Check multiple tasks for duplicates
|
|
114
|
+
*/
|
|
115
|
+
export async function checkDuplicates(tasks, repo, threshold = 0.8) {
|
|
116
|
+
const results = new Map();
|
|
117
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
118
|
+
const result = await checkDuplicate(tasks[i], repo, threshold);
|
|
119
|
+
results.set(i, result);
|
|
120
|
+
}
|
|
121
|
+
return results;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=duplicate-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duplicate-detector.js","sourceRoot":"","sources":["../../src/core/duplicate-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub CLI integration wrapper
|
|
3
|
+
*/
|
|
4
|
+
import { ParsedTask, IssueCreationResult } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Check if gh CLI is installed
|
|
7
|
+
*/
|
|
8
|
+
export declare function checkGhInstalled(): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Get current repository from git remote
|
|
11
|
+
*/
|
|
12
|
+
export declare function getCurrentRepo(): string | null;
|
|
13
|
+
/**
|
|
14
|
+
* Search for existing issues by keywords
|
|
15
|
+
*/
|
|
16
|
+
export declare function searchIssues(keywords: string, repo: string): Promise<any[]>;
|
|
17
|
+
/**
|
|
18
|
+
* Create a new GitHub issue
|
|
19
|
+
*/
|
|
20
|
+
export declare function createIssue(task: ParsedTask, repo: string, dryRun?: boolean): Promise<IssueCreationResult>;
|
|
21
|
+
/**
|
|
22
|
+
* Create a label if it doesn't exist
|
|
23
|
+
*/
|
|
24
|
+
export declare function createLabel(name: string, color: string, repo: string): Promise<boolean>;
|
|
25
|
+
/**
|
|
26
|
+
* List all repository labels
|
|
27
|
+
*/
|
|
28
|
+
export declare function listLabels(repo: string): Promise<{
|
|
29
|
+
name: string;
|
|
30
|
+
color: string;
|
|
31
|
+
}[]>;
|
|
32
|
+
/**
|
|
33
|
+
* Ensure required labels exist in the repository
|
|
34
|
+
*/
|
|
35
|
+
export declare function ensureLabelsExist(repo: string, labelColors: {
|
|
36
|
+
[key: string]: string;
|
|
37
|
+
}): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Create custom labels from tasks
|
|
40
|
+
*/
|
|
41
|
+
export declare function ensureCustomLabels(tasks: ParsedTask[], repo: string, defaultColor?: string): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Check if user is authenticated with gh CLI
|
|
44
|
+
*/
|
|
45
|
+
export declare function checkGhAuth(): boolean;
|
|
46
|
+
//# sourceMappingURL=github.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/core/github.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAG7D;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAO1C;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAU9C;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAcjF;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,OAAe,GACtB,OAAO,CAAC,mBAAmB,CAAC,CAoD9B;AAUD;;GAEG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC,CAiBlB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAWzF;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB3G;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,UAAU,EAAE,EACnB,IAAI,EAAE,MAAM,EACZ,YAAY,GAAE,MAAiB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,OAAO,CAOrC"}
|