@git-ai/cli 1.0.2 → 1.0.4

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.
@@ -1,39 +1,39 @@
1
- import { readFileSync } from "fs";
2
-
3
- /**
4
- * 查找冲突文件
5
- */
6
- export const findConflictFiles = (paths, workingPrefix = "") => {
7
- const conflictFiles = [];
8
- const ignoreFiles = [];
9
- const pathsCopy = [...paths];
10
-
11
- while (pathsCopy.length) {
12
- const p = pathsCopy.shift();
13
-
14
- // 如果有 workingPrefix,检查文件是否在当前工作目录下
15
- // p 是相对于 Git 根目录的路径,workingPrefix 也是相对于 Git 根目录的路径
16
- if (workingPrefix && !p.startsWith(workingPrefix)) {
17
- ignoreFiles.push(p);
18
- continue;
19
- }
20
-
21
- try {
22
- const content = readFileSync(p, "utf8");
23
- // 检查是否有 git 冲突标记
24
- // 仅当冲突标记出现在行首时才判定为真实冲突,避免代码字符串中的误判
25
- const hasStartMarker = /^<<<<<<< [^\n\r]*/m.test(content);
26
- const hasMidMarker = /^=======$/m.test(content);
27
- const hasEndMarker = /^>>>>>>> [^\n\r]*/m.test(content);
28
-
29
- if (hasStartMarker && hasMidMarker && hasEndMarker) {
30
- conflictFiles.push(p);
31
- }
32
- } catch (error) {
33
- // 文件读取失败,可能是被忽略的文件
34
- ignoreFiles.push(p);
35
- }
36
- }
37
-
38
- return { conflictFiles, ignoreFiles };
39
- };
1
+ import { readFileSync } from 'fs';
2
+
3
+ /**
4
+ * 查找冲突文件
5
+ */
6
+ export const findConflictFiles = (paths, workingPrefix = '') => {
7
+ const conflictFiles = [];
8
+ const ignoreFiles = [];
9
+ const pathsCopy = [...paths];
10
+
11
+ while (pathsCopy.length) {
12
+ const p = pathsCopy.shift();
13
+
14
+ // 如果有 workingPrefix,检查文件是否在当前工作目录下
15
+ // p 是相对于 Git 根目录的路径,workingPrefix 也是相对于 Git 根目录的路径
16
+ if (workingPrefix && !p.startsWith(workingPrefix)) {
17
+ ignoreFiles.push(p);
18
+ continue;
19
+ }
20
+
21
+ try {
22
+ const content = readFileSync(p, 'utf8');
23
+ // 检查是否有 git 冲突标记
24
+ // 仅当冲突标记出现在行首时才判定为真实冲突,避免代码字符串中的误判
25
+ const hasStartMarker = /^<<<<<<< [^\n\r]*/m.test(content);
26
+ const hasMidMarker = /^=======$/m.test(content);
27
+ const hasEndMarker = /^>>>>>>> [^\n\r]*/m.test(content);
28
+
29
+ if (hasStartMarker && hasMidMarker && hasEndMarker) {
30
+ conflictFiles.push(p);
31
+ }
32
+ } catch (error) {
33
+ // 文件读取失败,可能是被忽略的文件
34
+ ignoreFiles.push(p);
35
+ }
36
+ }
37
+
38
+ return { conflictFiles, ignoreFiles };
39
+ };
package/src/utils/Log.mjs CHANGED
@@ -1,146 +1,138 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import os from "os";
4
- import { NAME } from "../const.mjs";
5
- import npmlog from "npmlog";
6
-
7
- // 日志收集器
8
- const logCollector = [];
9
- const MAX_DETAIL_LENGTH = 2000;
10
-
11
- const truncate = (content = "") => {
12
- if (typeof content !== "string") {
13
- return content;
14
- }
15
- return content.length > MAX_DETAIL_LENGTH
16
- ? `${content.slice(0, MAX_DETAIL_LENGTH)}\n...[truncated]`
17
- : content;
18
- };
19
-
20
- const pushLog = (entry) => {
21
- logCollector.push({
22
- timestamp: new Date().toISOString(),
23
- ...entry,
24
- });
25
- };
26
-
27
- export function collectError(err, context = "") {
28
- const errorMessage = (err && (err.stack || err.message)) || String(err);
29
- pushLog({
30
- source: "error",
31
- level: "error",
32
- context,
33
- message: truncate(errorMessage),
34
- });
35
- }
36
-
37
- export function collectWarning(message = "", context = "") {
38
- pushLog({
39
- source: "warning",
40
- level: "warning",
41
- context,
42
- message: truncate(message),
43
- });
44
- }
45
-
46
- export function collectGitExecLog(entry = {}) {
47
- const {
48
- command = "",
49
- options = {},
50
- status = "success",
51
- output = "",
52
- error = "",
53
- } = entry;
54
- pushLog({
55
- source: "git-exec",
56
- level: status,
57
- command,
58
- options,
59
- message: truncate(output),
60
- error: truncate(error),
61
- });
62
- }
63
-
64
- export function collectLoggerLog(level, message) {
65
- const payload = Array.isArray(message) ? message : [message];
66
- pushLog({
67
- source: "logger",
68
- level,
69
- message: truncate(payload.filter(Boolean).join(" ")),
70
- });
71
- }
72
-
73
- export function collectSpinnerState(state, text = "") {
74
- pushLog({
75
- source: "spinner",
76
- level: state,
77
- message: truncate(text),
78
- });
79
- }
80
-
81
- export function writeLogFile() {
82
- if (logCollector.length === 0) {
83
- return null;
84
- }
85
-
86
- const now = new Date();
87
- const year = now.getFullYear();
88
- const month = String(now.getMonth() + 1).padStart(2, "0");
89
- const logDir = path.join(
90
- os.homedir(),
91
- ".config",
92
- NAME.replace("@", "/"),
93
- "logs",
94
- `${year}-${month}`
95
- );
96
-
97
- if (!fs.existsSync(logDir)) {
98
- fs.mkdirSync(logDir, { recursive: true });
99
- }
100
-
101
- const day = String(now.getDate()).padStart(2, "0");
102
- const hour = String(now.getHours()).padStart(2, "0");
103
- const minute = String(now.getMinutes()).padStart(2, "0");
104
- const second = String(now.getSeconds()).padStart(2, "0");
105
- const dateStr = `${year}-${month}-${day}_${hour}-${minute}-${second}`;
106
- const logFile = path.join(logDir, `log-${dateStr}.txt`);
107
-
108
- let logContent = `日志收集器\n生成时间: ${now.toLocaleString("zh-CN")}\n`;
109
- logContent += `${"=".repeat(80)}\n\n`;
110
-
111
- logCollector.forEach((item, index) => {
112
- logContent += `[日志 ${index + 1}]\n`;
113
- logContent += `时间: ${item.timestamp}\n`;
114
- logContent += `来源: ${item.source}\n`;
115
- if (item.level) {
116
- logContent += `级别: ${item.level}\n`;
117
- }
118
- if (item.context) {
119
- logContent += `上下文: ${item.context}\n`;
120
- }
121
- if (item.command) {
122
- logContent += `命令: ${item.command}\n`;
123
- }
124
- if (item.options && Object.keys(item.options).length) {
125
- logContent += `参数: ${JSON.stringify(item.options)}\n`;
126
- }
127
- if (item.message) {
128
- logContent += `内容:\n${item.message}\n`;
129
- }
130
- if (item.error) {
131
- logContent += `错误:\n${item.error}\n`;
132
- }
133
- logContent += `${"-".repeat(80)}\n\n`;
134
- });
135
-
136
- fs.writeFileSync(logFile, logContent, "utf8");
137
-
138
- const errorCount = logCollector.filter(
139
- (item) => item.level === "error"
140
- ).length;
141
- if (errorCount > 0) {
142
- npmlog.verbose(`日志地址: ${logFile}`);
143
- }
144
-
145
- return logFile;
146
- }
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import { NAME } from '../const.mjs';
5
+ import npmlog from 'npmlog';
6
+
7
+ // 日志收集器
8
+ const logCollector = [];
9
+ const MAX_DETAIL_LENGTH = 2000;
10
+
11
+ const truncate = (content = '') => {
12
+ if (typeof content !== 'string') {
13
+ return content;
14
+ }
15
+ return content.length > MAX_DETAIL_LENGTH
16
+ ? `${content.slice(0, MAX_DETAIL_LENGTH)}\n...[truncated]`
17
+ : content;
18
+ };
19
+
20
+ const pushLog = (entry) => {
21
+ logCollector.push({
22
+ timestamp: new Date().toISOString(),
23
+ ...entry,
24
+ });
25
+ };
26
+
27
+ export function collectError(err, context = '') {
28
+ const errorMessage = (err && (err.stack || err.message)) || String(err);
29
+ pushLog({
30
+ source: 'error',
31
+ level: 'error',
32
+ context,
33
+ message: truncate(errorMessage),
34
+ });
35
+ }
36
+
37
+ export function collectWarning(message = '', context = '') {
38
+ pushLog({
39
+ source: 'warning',
40
+ level: 'warning',
41
+ context,
42
+ message: truncate(message),
43
+ });
44
+ }
45
+
46
+ export function collectGitExecLog(entry = {}) {
47
+ const { command = '', options = {}, status = 'success', output = '', error = '' } = entry;
48
+ pushLog({
49
+ source: 'git-exec',
50
+ level: status,
51
+ command,
52
+ options,
53
+ message: truncate(output),
54
+ error: truncate(error),
55
+ });
56
+ }
57
+
58
+ export function collectLoggerLog(level, message) {
59
+ const payload = Array.isArray(message) ? message : [message];
60
+ pushLog({
61
+ source: 'logger',
62
+ level,
63
+ message: truncate(payload.filter(Boolean).join(' ')),
64
+ });
65
+ }
66
+
67
+ export function collectSpinnerState(state, text = '') {
68
+ pushLog({
69
+ source: 'spinner',
70
+ level: state,
71
+ message: truncate(text),
72
+ });
73
+ }
74
+
75
+ export function writeLogFile() {
76
+ if (logCollector.length === 0) {
77
+ return null;
78
+ }
79
+
80
+ const now = new Date();
81
+ const year = now.getFullYear();
82
+ const month = String(now.getMonth() + 1).padStart(2, '0');
83
+ const logDir = path.join(
84
+ os.homedir(),
85
+ '.config',
86
+ NAME.replace('@', '/'),
87
+ 'logs',
88
+ `${year}-${month}`
89
+ );
90
+
91
+ if (!fs.existsSync(logDir)) {
92
+ fs.mkdirSync(logDir, { recursive: true });
93
+ }
94
+
95
+ const day = String(now.getDate()).padStart(2, '0');
96
+ const hour = String(now.getHours()).padStart(2, '0');
97
+ const minute = String(now.getMinutes()).padStart(2, '0');
98
+ const second = String(now.getSeconds()).padStart(2, '0');
99
+ const dateStr = `${year}-${month}-${day}_${hour}-${minute}-${second}`;
100
+ const logFile = path.join(logDir, `log-${dateStr}.txt`);
101
+
102
+ let logContent = `日志收集器\n生成时间: ${now.toLocaleString('zh-CN')}\n`;
103
+ logContent += `${'='.repeat(80)}\n\n`;
104
+
105
+ logCollector.forEach((item, index) => {
106
+ logContent += `[日志 ${index + 1}]\n`;
107
+ logContent += `时间: ${item.timestamp}\n`;
108
+ logContent += `来源: ${item.source}\n`;
109
+ if (item.level) {
110
+ logContent += `级别: ${item.level}\n`;
111
+ }
112
+ if (item.context) {
113
+ logContent += `上下文: ${item.context}\n`;
114
+ }
115
+ if (item.command) {
116
+ logContent += `命令: ${item.command}\n`;
117
+ }
118
+ if (item.options && Object.keys(item.options).length) {
119
+ logContent += `参数: ${JSON.stringify(item.options)}\n`;
120
+ }
121
+ if (item.message) {
122
+ logContent += `内容:\n${item.message}\n`;
123
+ }
124
+ if (item.error) {
125
+ logContent += `错误:\n${item.error}\n`;
126
+ }
127
+ logContent += `${'-'.repeat(80)}\n\n`;
128
+ });
129
+
130
+ fs.writeFileSync(logFile, logContent, 'utf8');
131
+
132
+ const errorCount = logCollector.filter((item) => item.level === 'error').length;
133
+ if (errorCount > 0) {
134
+ npmlog.verbose(`日志地址: ${logFile}`);
135
+ }
136
+
137
+ return logFile;
138
+ }
@@ -1,34 +1,34 @@
1
- import npmlog from "npmlog";
2
- import { BIN } from "../const.mjs";
3
- import { collectLoggerLog } from "./Log.mjs";
4
-
5
- npmlog.level = "info";
6
- npmlog.heading = BIN.replace(" ", "-"); // 修改前缀
7
- npmlog.headingStyle = { fg: "red", bg: "black" }; // 修改前缀样式
8
- npmlog.addLevel("success", 2000, { fg: "green", bold: true }); // 添加自定义命令
9
- npmlog.addLevel("verbose", 2000, { fg: "blue", bg: "black" }, "verb"); // 添加自定义命令,Number 数字1000会无法显示,建议2000
10
-
11
- const levelsToWrap = [
12
- "info",
13
- "warn",
14
- "error",
15
- "success",
16
- "verb",
17
- "verbose",
18
- "silly",
19
- "http",
20
- "notice",
21
- ];
22
-
23
- levelsToWrap.forEach((level) => {
24
- if (typeof npmlog[level] !== "function") {
25
- return;
26
- }
27
- const original = npmlog[level].bind(npmlog);
28
- npmlog[level] = (...args) => {
29
- collectLoggerLog(level, args);
30
- return original(...args);
31
- };
32
- });
33
-
34
- export default npmlog;
1
+ import npmlog from 'npmlog';
2
+ import { BIN } from '../const.mjs';
3
+ import { collectLoggerLog } from './Log.mjs';
4
+
5
+ npmlog.level = 'info';
6
+ npmlog.heading = BIN.replace(' ', '-'); // 修改前缀
7
+ npmlog.headingStyle = { fg: 'red', bg: 'black' }; // 修改前缀样式
8
+ npmlog.addLevel('success', 2000, { fg: 'green', bold: true }); // 添加自定义命令
9
+ npmlog.addLevel('verbose', 2000, { fg: 'blue', bg: 'black' }, 'verb'); // 添加自定义命令,Number 数字1000会无法显示,建议2000
10
+
11
+ const levelsToWrap = [
12
+ 'info',
13
+ 'warn',
14
+ 'error',
15
+ 'success',
16
+ 'verb',
17
+ 'verbose',
18
+ 'silly',
19
+ 'http',
20
+ 'notice',
21
+ ];
22
+
23
+ levelsToWrap.forEach((level) => {
24
+ if (typeof npmlog[level] !== 'function') {
25
+ return;
26
+ }
27
+ const original = npmlog[level].bind(npmlog);
28
+ npmlog[level] = (...args) => {
29
+ collectLoggerLog(level, args);
30
+ return original(...args);
31
+ };
32
+ });
33
+
34
+ export default npmlog;