@itcase/config 1.7.25 → 1.7.26
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/package.json +16 -16
- package/smart-commit/cli.js +127 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itcase/config",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.26",
|
|
4
4
|
"author": "ITCase",
|
|
5
5
|
"description": "ITCase Config",
|
|
6
6
|
"engines": {
|
|
@@ -43,11 +43,11 @@
|
|
|
43
43
|
"@commitlint/config-conventional": "^21.2.3",
|
|
44
44
|
"@commitlint/cz-commitlint": "^21.2.3",
|
|
45
45
|
"@lehoczky/postcss-fluid": "^1.0.3",
|
|
46
|
-
"@lerna-lite/cli": "^5.6.
|
|
47
|
-
"@lerna-lite/exec": "^5.6.
|
|
48
|
-
"@lerna-lite/list": "^5.6.
|
|
49
|
-
"@lerna-lite/run": "^5.6.
|
|
50
|
-
"@lerna-lite/watch": "^5.6.
|
|
46
|
+
"@lerna-lite/cli": "^5.6.3",
|
|
47
|
+
"@lerna-lite/exec": "^5.6.3",
|
|
48
|
+
"@lerna-lite/list": "^5.6.3",
|
|
49
|
+
"@lerna-lite/run": "^5.6.3",
|
|
50
|
+
"@lerna-lite/watch": "^5.6.3",
|
|
51
51
|
"@rollup/plugin-alias": "^6.0.0",
|
|
52
52
|
"@rollup/plugin-babel": "^7.1.0",
|
|
53
53
|
"@rollup/plugin-commonjs": "^29.0.3",
|
|
@@ -68,11 +68,11 @@
|
|
|
68
68
|
"commitizen": "^4.3.2",
|
|
69
69
|
"conventional-changelog-conventionalcommits": "9.3.1",
|
|
70
70
|
"conventional-changelog-writer": "9.3.0",
|
|
71
|
-
"cssnano": "^9.
|
|
72
|
-
"cssnano-preset-default": "^9.
|
|
71
|
+
"cssnano": "^9.8.0",
|
|
72
|
+
"cssnano-preset-default": "^9.8.0",
|
|
73
73
|
"inquirer": "^14.2.3",
|
|
74
74
|
"log-update": "^8.0.0",
|
|
75
|
-
"postcss": "^8.5.
|
|
75
|
+
"postcss": "^8.5.30",
|
|
76
76
|
"postcss-aspect-ratio-polyfill": "^2.0.0",
|
|
77
77
|
"postcss-clamp": "^4.1.0",
|
|
78
78
|
"postcss-cli": "^12.0.0",
|
|
@@ -80,19 +80,19 @@
|
|
|
80
80
|
"postcss-combine-duplicated-selectors": "^11.0.0",
|
|
81
81
|
"postcss-convert-unit": "^0.1.3",
|
|
82
82
|
"postcss-dark-theme-class": "^2.0.0",
|
|
83
|
-
"postcss-discard-duplicates": "^9.0.
|
|
83
|
+
"postcss-discard-duplicates": "^9.0.7",
|
|
84
84
|
"postcss-each": "^1.1.0",
|
|
85
85
|
"postcss-easings": "^4.0.0",
|
|
86
86
|
"postcss-extend-rule": "^4.0.0",
|
|
87
87
|
"postcss-flexbugs-fixes": "^5.0.2",
|
|
88
88
|
"postcss-hexrgba": "^2.1.0",
|
|
89
|
-
"postcss-import": "^17.0.
|
|
89
|
+
"postcss-import": "^17.0.1",
|
|
90
90
|
"postcss-import-ext-glob": "^2.1.1",
|
|
91
91
|
"postcss-loader": "^8.2.1",
|
|
92
92
|
"postcss-merge-at-rules": "^2.0.1",
|
|
93
93
|
"postcss-mixins": "^12.1.2",
|
|
94
94
|
"postcss-mq-extract": "^1.0.0",
|
|
95
|
-
"postcss-nested": "^
|
|
95
|
+
"postcss-nested": "^9.0.0",
|
|
96
96
|
"postcss-nested-ancestors": "^3.0.0",
|
|
97
97
|
"postcss-normalize": "^13.0.1",
|
|
98
98
|
"postcss-prepend-imports": "^1.0.1",
|
|
@@ -110,17 +110,17 @@
|
|
|
110
110
|
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
111
111
|
"rollup-preserve-directives": "^1.1.3",
|
|
112
112
|
"semantic-release": "^25.0.9",
|
|
113
|
-
"semantic-release-lerna": "^3.6.
|
|
113
|
+
"semantic-release-lerna": "^3.6.7"
|
|
114
114
|
},
|
|
115
115
|
"devDependencies": {
|
|
116
116
|
"@itcase/agent-skills": "^1.0.13",
|
|
117
|
-
"@itcase/lint": "^1.1.
|
|
117
|
+
"@itcase/lint": "^1.1.130",
|
|
118
118
|
"eslint": "9.39.2",
|
|
119
119
|
"husky": "^9.1.7",
|
|
120
120
|
"inquirer": "^14.2.3",
|
|
121
121
|
"lint-staged": "^17.6.0",
|
|
122
|
-
"prettier": "^3.9.
|
|
123
|
-
"storybook": "^10.6.
|
|
122
|
+
"prettier": "^3.9.10",
|
|
123
|
+
"storybook": "^10.6.2",
|
|
124
124
|
"stylelint": "^17.16.0",
|
|
125
125
|
"typescript": "^6.0.3"
|
|
126
126
|
}
|
package/smart-commit/cli.js
CHANGED
|
@@ -24,10 +24,18 @@ const CLI_RELATIVE = 'smart-commit/cli.js'
|
|
|
24
24
|
// Cheap Cursor Models pool — commit messages do not need Auto / frontier models.
|
|
25
25
|
const DEFAULT_MODEL = 'composer-2.5'
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
// A small change set still sends the patch. A large tree used to be many
|
|
28
|
+
// agent calls with up to 80k chars of diff each. Compact numstat keeps that
|
|
29
|
+
// to one call.
|
|
30
|
+
const MAX_DIFF = 20_000
|
|
31
|
+
const COMPACT_SUMMARY_MAX = 12_000
|
|
32
|
+
const SMALL_PLAN_FILES = 12
|
|
33
|
+
const PER_FILE_EXCERPT = 500
|
|
34
|
+
const EXCERPT_SKIP_LINES = 400
|
|
35
|
+
const EXCERPT_MAX_BYTES = 256 * 1024
|
|
28
36
|
const GIT_MAX_BUFFER = 32 * 1024 * 1024
|
|
29
37
|
const GIT_PATH_BATCH = 40
|
|
30
|
-
const PLAN_FILE_BATCH =
|
|
38
|
+
const PLAN_FILE_BATCH = 250
|
|
31
39
|
const ARG_SAFE = 100_000
|
|
32
40
|
const LOCKFILE_NAMES = new Set([
|
|
33
41
|
'package-lock.json',
|
|
@@ -608,8 +616,10 @@ function buildPrompt(scopes, types, files, cwd, type) {
|
|
|
608
616
|
|
|
609
617
|
const sourceFiles = files.filter((file) => !isLockfile(file))
|
|
610
618
|
const lockFiles = files.filter((file) => isLockfile(file))
|
|
619
|
+
const diffLimit =
|
|
620
|
+
sourceFiles.length > SMALL_PLAN_FILES ? COMPACT_SUMMARY_MAX : MAX_DIFF
|
|
611
621
|
let diff = buildSourceDiff(cwd, sourceFiles)
|
|
612
|
-
if (diff.length >
|
|
622
|
+
if (diff.length > diffLimit) diff = `${diff.slice(0, diffLimit)}\n…truncated`
|
|
613
623
|
|
|
614
624
|
return `Plan git commits. Do not edit files or run git commit.
|
|
615
625
|
Return ONLY JSON: {"commits":[{"message":"type(scope): subject","files":["a.ts"]}]}
|
|
@@ -622,6 +632,7 @@ Prefer one commit when changes belong to the same feature.
|
|
|
622
632
|
Split by scope. Each listed file in exactly one commit — including deleted files (D) and new/untracked files (??).
|
|
623
633
|
Put each lockfile in the same commit as its sibling package.json. Do not make a lockfile-only commit.
|
|
624
634
|
Do not add Co-authored-by or Made-with trailers.
|
|
635
|
+
Do not use tools or read files. The file list and diff below are the only source.
|
|
625
636
|
${type ? `Prefer type "${type}".\n` : ''}Files:
|
|
626
637
|
${files
|
|
627
638
|
.map((file) => {
|
|
@@ -644,6 +655,11 @@ ${diff || '(none)'}
|
|
|
644
655
|
}
|
|
645
656
|
|
|
646
657
|
function buildSourceDiff(cwd, files) {
|
|
658
|
+
if (files.length > SMALL_PLAN_FILES) return buildCompactSourceDiff(cwd, files)
|
|
659
|
+
return buildFullSourceDiff(cwd, files, MAX_DIFF)
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
function buildFullSourceDiff(cwd, files, limit) {
|
|
647
663
|
const tracked = []
|
|
648
664
|
const untracked = []
|
|
649
665
|
for (const file of files) {
|
|
@@ -654,13 +670,13 @@ function buildSourceDiff(cwd, files) {
|
|
|
654
670
|
const parts = []
|
|
655
671
|
let used = 0
|
|
656
672
|
const pushLimited = (text) => {
|
|
657
|
-
if (used >=
|
|
673
|
+
if (used >= limit) return false
|
|
658
674
|
// Empty batch (no changes / ENOBUFS skip) — keep scanning remaining files.
|
|
659
675
|
if (!text) return true
|
|
660
|
-
const room =
|
|
676
|
+
const room = limit - used
|
|
661
677
|
if (text.length > room) {
|
|
662
678
|
parts.push(`${text.slice(0, room)}\n…truncated`)
|
|
663
|
-
used =
|
|
679
|
+
used = limit
|
|
664
680
|
return false
|
|
665
681
|
}
|
|
666
682
|
parts.push(text)
|
|
@@ -669,17 +685,120 @@ function buildSourceDiff(cwd, files) {
|
|
|
669
685
|
}
|
|
670
686
|
|
|
671
687
|
forEachBatch(tracked, (batch) => {
|
|
672
|
-
if (used >=
|
|
688
|
+
if (used >= limit) return false
|
|
673
689
|
return pushLimited(tryOut(cwd, ['diff', 'HEAD', '--', ...batch]))
|
|
674
690
|
})
|
|
675
691
|
for (const file of untracked) {
|
|
676
|
-
if (used >=
|
|
692
|
+
if (used >= limit) break
|
|
677
693
|
const piece = buildUntrackedDiff(cwd, file)
|
|
678
694
|
if (!pushLimited(piece)) break
|
|
679
695
|
}
|
|
680
696
|
return parts.join('\n\n')
|
|
681
697
|
}
|
|
682
698
|
|
|
699
|
+
function buildCompactSourceDiff(cwd, files) {
|
|
700
|
+
const tracked = []
|
|
701
|
+
const untracked = new Set()
|
|
702
|
+
for (const file of files) {
|
|
703
|
+
if (isUntracked(cwd, file)) untracked.add(file)
|
|
704
|
+
else tracked.push(file)
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
const statLines = []
|
|
708
|
+
forEachBatch(tracked, (batch) => {
|
|
709
|
+
const text = tryOut(cwd, ['diff', '--numstat', 'HEAD', '--', ...batch])
|
|
710
|
+
if (text) statLines.push(...text.split('\n').filter(Boolean))
|
|
711
|
+
})
|
|
712
|
+
for (const file of untracked) statLines.push(untrackedNumstatLine(cwd, file))
|
|
713
|
+
|
|
714
|
+
const weightByFile = new Map()
|
|
715
|
+
for (const line of statLines) {
|
|
716
|
+
const file = line.split('\t').slice(2).join('\t')
|
|
717
|
+
weightByFile.set(file, parseNumstatWeight(line))
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
const header = `numstat (added, removed, path):\n${statLines.join('\n')}`
|
|
721
|
+
if (header.length >= COMPACT_SUMMARY_MAX) {
|
|
722
|
+
return `${header.slice(0, COMPACT_SUMMARY_MAX)}\n…truncated`
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
const ranked = [...files].sort((left, right) => {
|
|
726
|
+
const leftWeight = weightByFile.get(left)
|
|
727
|
+
const rightWeight = weightByFile.get(right)
|
|
728
|
+
return (rightWeight ?? -1) - (leftWeight ?? -1)
|
|
729
|
+
})
|
|
730
|
+
|
|
731
|
+
const excerptHeader = '\n\nchanged lines:\n'
|
|
732
|
+
let room = COMPACT_SUMMARY_MAX - header.length - excerptHeader.length
|
|
733
|
+
const excerpts = []
|
|
734
|
+
for (const file of ranked) {
|
|
735
|
+
if (room < 40) break
|
|
736
|
+
const weight = weightByFile.get(file)
|
|
737
|
+
if (weight == null || weight > EXCERPT_SKIP_LINES) continue
|
|
738
|
+
if (weight === 0 && !untracked.has(file)) continue
|
|
739
|
+
const excerpt = changedLineExcerpt(
|
|
740
|
+
cwd,
|
|
741
|
+
file,
|
|
742
|
+
untracked.has(file),
|
|
743
|
+
Math.min(PER_FILE_EXCERPT, room),
|
|
744
|
+
)
|
|
745
|
+
if (!excerpt) continue
|
|
746
|
+
excerpts.push(excerpt)
|
|
747
|
+
room -= excerpt.length + 1
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
if (!excerpts.length) return header
|
|
751
|
+
return `${header}${excerptHeader}${excerpts.join('\n')}`
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
function parseNumstatWeight(line) {
|
|
755
|
+
const [added, removed] = line.split('\t')
|
|
756
|
+
if (added === '-' || removed === '-') return null
|
|
757
|
+
return (Number(added) || 0) + (Number(removed) || 0)
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
function untrackedNumstatLine(cwd, file) {
|
|
761
|
+
const text = readTextFileHead(cwd, file)
|
|
762
|
+
if (text == null) return `-\t-\t${file}`
|
|
763
|
+
const lines = text ? text.split('\n').length : 0
|
|
764
|
+
return `${lines}\t0\t${file}`
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
function readTextFileHead(cwd, file) {
|
|
768
|
+
const filePath = path.join(cwd, file)
|
|
769
|
+
let stat
|
|
770
|
+
try {
|
|
771
|
+
stat = fs.statSync(filePath)
|
|
772
|
+
} catch {
|
|
773
|
+
return null
|
|
774
|
+
}
|
|
775
|
+
if (!stat.isFile() || stat.size > EXCERPT_MAX_BYTES) return null
|
|
776
|
+
const buffer = fs.readFileSync(filePath)
|
|
777
|
+
if (buffer.includes(0)) return null
|
|
778
|
+
return buffer.toString('utf8')
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
function changedLineExcerpt(cwd, file, untracked, cap) {
|
|
782
|
+
if (untracked) {
|
|
783
|
+
const text = readTextFileHead(cwd, file)
|
|
784
|
+
if (!text) return ''
|
|
785
|
+
const body = text.length > cap ? `${text.slice(0, cap)}…` : text
|
|
786
|
+
return `${file}:\n${body}`
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
const raw = tryOut(cwd, ['diff', '-U0', '--no-color', 'HEAD', '--', file])
|
|
790
|
+
if (!raw) return ''
|
|
791
|
+
const lines = []
|
|
792
|
+
for (const line of raw.split('\n')) {
|
|
793
|
+
if (line.startsWith('+++') || line.startsWith('---')) continue
|
|
794
|
+
if (line.startsWith('+') || line.startsWith('-')) lines.push(line)
|
|
795
|
+
}
|
|
796
|
+
if (!lines.length) return ''
|
|
797
|
+
let body = lines.join('\n')
|
|
798
|
+
if (body.length > cap) body = `${body.slice(0, cap)}…`
|
|
799
|
+
return `${file}:\n${body}`
|
|
800
|
+
}
|
|
801
|
+
|
|
683
802
|
function buildUntrackedDiff(cwd, file) {
|
|
684
803
|
const filePath = path.join(cwd, file)
|
|
685
804
|
if (!fs.existsSync(filePath)) return ''
|