@itcase/config 1.7.17 → 1.7.19
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 +1 -1
- package/package.json +12 -12
- package/semantic-release/index.js +2 -0
- package/semantic-release/semanticReleaseBot.js +16 -0
- package/smart-commit/cli.js +94 -14
package/README.md
CHANGED
|
@@ -103,7 +103,7 @@ npm install --save-dev commitizen @commitlint/cz-commitlint
|
|
|
103
103
|
|
|
104
104
|
## Smart commit
|
|
105
105
|
|
|
106
|
-
`smart-commit` — Cursor Agent (`ask`) планирует коммиты по `SCOPES`, печатает сообщения, спрашивает `[y/N]`. Перед вызовом агента
|
|
106
|
+
`smart-commit` — Cursor Agent (`ask`) планирует коммиты по `SCOPES`, печатает сообщения, спрашивает `[y/N]`. Перед вызовом агента запускаются те же проверки, что у husky в lint-staged. Сначала eslint и stylelint по изменённым js/ts/css/mdx (с `--fix`, как в хуке): если линтер падает, агент не вызывается и ни один коммит не создаётся. Затем проверка типов: `tsc --noEmit --pretty`, либо `npm run typecheck`, если конфиг — `lintStagedMonorepo`. Typecheck идёт только когда среди изменений есть существующие `.ts`/`.tsx`. `--no-verify` пропускает и эти проверки, и хуки. Перед коммитом CLI ждёт и снимает устаревший `.git/index.lock`, если его никто не держит. Lockfile (`package-lock.json` и аналоги) всегда кладётся в тот же коммит, что и соседний `package.json`; при одном только bump deps агент не вызывается.
|
|
107
107
|
|
|
108
108
|
```text
|
|
109
109
|
[random pixel animation]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itcase/config",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.19",
|
|
4
4
|
"author": "ITCase",
|
|
5
5
|
"description": "ITCase Config",
|
|
6
6
|
"engines": {
|
|
@@ -67,20 +67,20 @@
|
|
|
67
67
|
"chokidar-cli": "^3.0.0",
|
|
68
68
|
"commitizen": "^4.3.2",
|
|
69
69
|
"conventional-changelog-conventionalcommits": "9.3.1",
|
|
70
|
-
"conventional-changelog-writer": "9.
|
|
71
|
-
"cssnano": "^9.
|
|
72
|
-
"cssnano-preset-default": "^9.
|
|
73
|
-
"inquirer": "^14.2.
|
|
70
|
+
"conventional-changelog-writer": "9.3.0",
|
|
71
|
+
"cssnano": "^9.3.2",
|
|
72
|
+
"cssnano-preset-default": "^9.3.2",
|
|
73
|
+
"inquirer": "^14.2.3",
|
|
74
74
|
"log-update": "^8.0.0",
|
|
75
|
-
"postcss": "^8.5.
|
|
75
|
+
"postcss": "^8.5.29",
|
|
76
76
|
"postcss-aspect-ratio-polyfill": "^2.0.0",
|
|
77
77
|
"postcss-clamp": "^4.1.0",
|
|
78
78
|
"postcss-cli": "^12.0.0",
|
|
79
79
|
"postcss-color-hsla-fallback": "^1.0.0",
|
|
80
|
-
"postcss-combine-duplicated-selectors": "^
|
|
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.5",
|
|
84
84
|
"postcss-each": "^1.1.0",
|
|
85
85
|
"postcss-easings": "^4.0.0",
|
|
86
86
|
"postcss-extend-rule": "^4.0.0",
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
"postcss-nested-ancestors": "^3.0.0",
|
|
97
97
|
"postcss-normalize": "^13.0.1",
|
|
98
98
|
"postcss-prepend-imports": "^1.0.1",
|
|
99
|
-
"postcss-preset-env": "^11.
|
|
99
|
+
"postcss-preset-env": "^11.6.1",
|
|
100
100
|
"postcss-pxtorem": "^6.1.0",
|
|
101
101
|
"postcss-sort-media-queries": "^6.7.1",
|
|
102
102
|
"postcss-unit": "^0.0.3",
|
|
@@ -117,11 +117,11 @@
|
|
|
117
117
|
"@itcase/lint": "^1.1.126",
|
|
118
118
|
"eslint": "9.39.2",
|
|
119
119
|
"husky": "^9.1.7",
|
|
120
|
-
"inquirer": "^14.2.
|
|
120
|
+
"inquirer": "^14.2.3",
|
|
121
121
|
"lint-staged": "^17.6.0",
|
|
122
122
|
"prettier": "^3.9.9",
|
|
123
|
-
"storybook": "^10.6.
|
|
124
|
-
"stylelint": "^17.
|
|
123
|
+
"storybook": "^10.6.1",
|
|
124
|
+
"stylelint": "^17.16.0",
|
|
125
125
|
"typescript": "^6.0.3"
|
|
126
126
|
}
|
|
127
127
|
}
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
createSemanticReleaseApp,
|
|
3
3
|
semanticReleaseApp,
|
|
4
4
|
} from './semanticReleaseApp.js'
|
|
5
|
+
import { semanticReleaseBot } from './semanticReleaseBot.js'
|
|
5
6
|
import { semanticReleaseMonorepo } from './semanticReleaseMonorepo.js'
|
|
6
7
|
import { semanticReleasePackage } from './semanticReleasePackage.js'
|
|
7
8
|
import { semanticReleaseProject } from './semanticReleaseProject.js'
|
|
@@ -10,6 +11,7 @@ import { semanticReleaseVSMarketplace } from './semanticReleaseVSMarketplace.js'
|
|
|
10
11
|
export {
|
|
11
12
|
createSemanticReleaseApp,
|
|
12
13
|
semanticReleaseApp,
|
|
14
|
+
semanticReleaseBot,
|
|
13
15
|
semanticReleaseMonorepo,
|
|
14
16
|
semanticReleasePackage,
|
|
15
17
|
semanticReleaseProject,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createSemanticReleaseConfig } from './common.js'
|
|
2
|
+
|
|
3
|
+
// Тот же релиз, что у проекта: ветка docker/master, без публикации в npm.
|
|
4
|
+
// Отдельного репозитория задач нет, поэтому заметки собираются только из коммитов.
|
|
5
|
+
const semanticReleaseBot = createSemanticReleaseConfig({
|
|
6
|
+
branches: ['docker/master'],
|
|
7
|
+
gitConfig: {
|
|
8
|
+
message: 'release: publishing new version ${nextRelease.version} [skip ci]',
|
|
9
|
+
assets: ['package.json', 'package-lock.json', 'CHANGELOG.md'],
|
|
10
|
+
},
|
|
11
|
+
npmConfig: {
|
|
12
|
+
npmPublish: false,
|
|
13
|
+
},
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export { semanticReleaseBot }
|
package/smart-commit/cli.js
CHANGED
|
@@ -59,6 +59,20 @@ const LINT_STAGED_CONFIGS = [
|
|
|
59
59
|
'.lintstagedrc.cjs',
|
|
60
60
|
]
|
|
61
61
|
const LINT_STAGED_TS_KEY = '*.{js,jsx,mjs,cjs,ts,tsx}'
|
|
62
|
+
const LINT_STAGED_FILE_GROUPS = [
|
|
63
|
+
{
|
|
64
|
+
key: LINT_STAGED_TS_KEY,
|
|
65
|
+
test: /\.(?:js|jsx|mjs|cjs|ts|tsx)$/,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
key: '*.css',
|
|
69
|
+
test: /\.css$/,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
key: '*.mdx',
|
|
73
|
+
test: /\.mdx$/,
|
|
74
|
+
},
|
|
75
|
+
]
|
|
62
76
|
const AGENT_WAIT_STEPS = [
|
|
63
77
|
'Asking Cursor Agent',
|
|
64
78
|
'Still thinking',
|
|
@@ -76,10 +90,12 @@ Default model: ${DEFAULT_MODEL} (override with --model / SMART_COMMIT_MODEL).
|
|
|
76
90
|
(husky pre-commit / lint-staged and commit-msg). Commit message
|
|
77
91
|
is still checked by smart-commit before git runs.
|
|
78
92
|
|
|
79
|
-
Before the agent, the same
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
93
|
+
Before the agent, the same checks as husky lint-staged run.
|
|
94
|
+
eslint and stylelint (--fix) run on changed js/ts/css/mdx, then
|
|
95
|
+
typecheck when changes include .ts/.tsx (tsc --noEmit, or
|
|
96
|
+
npm run typecheck from lint-staged config). A lint or type
|
|
97
|
+
error exits before the agent is called and before any commit.
|
|
98
|
+
--no-verify skips these checks and the hooks.
|
|
83
99
|
|
|
84
100
|
Progress sprite is random (nyan cat, banana, or upyachka).
|
|
85
101
|
Force with --cat, --banana, or --upyachka. Agent log is below.
|
|
@@ -118,8 +134,10 @@ async function main(argv) {
|
|
|
118
134
|
return
|
|
119
135
|
}
|
|
120
136
|
|
|
121
|
-
// Husky typechecks in pre-commit
|
|
137
|
+
// Husky lints and typechecks in pre-commit. By then the agent has spent
|
|
138
|
+
// tokens and earlier commits in the plan may already exist.
|
|
122
139
|
if (!option.noVerify) {
|
|
140
|
+
await runHuskyLint(cwd, changedFiles)
|
|
123
141
|
await runHuskyTypecheck(cwd, changedFiles)
|
|
124
142
|
}
|
|
125
143
|
|
|
@@ -390,11 +408,78 @@ function readReleaseBranches(cwd) {
|
|
|
390
408
|
return match[1].split(/\s+/).filter(Boolean)
|
|
391
409
|
}
|
|
392
410
|
|
|
411
|
+
async function runHuskyLint(cwd, files) {
|
|
412
|
+
const commands = await lintCommandsForFiles(cwd, files)
|
|
413
|
+
if (!commands.length) return
|
|
414
|
+
|
|
415
|
+
for (const entry of commands) {
|
|
416
|
+
runShellCommand(
|
|
417
|
+
cwd,
|
|
418
|
+
'Lint',
|
|
419
|
+
lintDisplay(entry.command, entry.fileCount),
|
|
420
|
+
entry.command,
|
|
421
|
+
'Lint failed. Fix the errors above — the agent was not called.',
|
|
422
|
+
)
|
|
423
|
+
}
|
|
424
|
+
process.stdout.write('Lint passed.\n\n')
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
async function lintCommandsForFiles(cwd, files) {
|
|
428
|
+
const config = await loadLintStagedConfig(cwd)
|
|
429
|
+
if (!config) return []
|
|
430
|
+
|
|
431
|
+
const commands = []
|
|
432
|
+
for (const group of LINT_STAGED_FILE_GROUPS) {
|
|
433
|
+
const task = config[group.key]
|
|
434
|
+
if (typeof task !== 'function') continue
|
|
435
|
+
|
|
436
|
+
const matched = files.filter(
|
|
437
|
+
(file) => group.test.test(file) && fs.existsSync(path.resolve(cwd, file)),
|
|
438
|
+
)
|
|
439
|
+
if (!matched.length) continue
|
|
440
|
+
|
|
441
|
+
const absolute = matched.map((file) => path.resolve(cwd, file))
|
|
442
|
+
const result = await task(absolute)
|
|
443
|
+
const list = (Array.isArray(result) ? result : [result]).filter(
|
|
444
|
+
(command) => typeof command === 'string' && isLintCommand(command),
|
|
445
|
+
)
|
|
446
|
+
for (const command of list) {
|
|
447
|
+
commands.push({
|
|
448
|
+
command: command.trim(),
|
|
449
|
+
fileCount: matched.length,
|
|
450
|
+
})
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return commands
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function lintDisplay(command, fileCount) {
|
|
457
|
+
const tool = command.match(/"?(eslint|stylelint)\b/)?.[1] || 'lint'
|
|
458
|
+
const fix = /(?:^|\s)"?--fix"?(?:\s|$)/.test(command) ? ' --fix' : ''
|
|
459
|
+
const filesLabel = fileCount === 1 ? '1 file' : `${fileCount} files`
|
|
460
|
+
return `${tool}${fix} (${filesLabel})`
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function isLintCommand(command) {
|
|
464
|
+
return /^\s*"?(?:eslint|stylelint)\b/.test(command)
|
|
465
|
+
}
|
|
466
|
+
|
|
393
467
|
async function runHuskyTypecheck(cwd, files) {
|
|
394
468
|
const command = await typecheckCommandForFiles(cwd, files)
|
|
395
469
|
if (!command) return
|
|
396
470
|
|
|
397
|
-
|
|
471
|
+
runShellCommand(
|
|
472
|
+
cwd,
|
|
473
|
+
'Typecheck',
|
|
474
|
+
command,
|
|
475
|
+
command,
|
|
476
|
+
'Typecheck failed. Fix the errors above — the agent was not called.',
|
|
477
|
+
)
|
|
478
|
+
process.stdout.write('Typecheck passed.\n\n')
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function runShellCommand(cwd, label, displayCommand, command, failMessage) {
|
|
482
|
+
process.stdout.write(`${paint('1', label)} ${dim(displayCommand)}\n`)
|
|
398
483
|
const bin = path.join(cwd, 'node_modules', '.bin')
|
|
399
484
|
const result = spawnSync(command, {
|
|
400
485
|
cwd: cwd,
|
|
@@ -406,14 +491,11 @@ async function runHuskyTypecheck(cwd, files) {
|
|
|
406
491
|
stdio: 'inherit',
|
|
407
492
|
})
|
|
408
493
|
if (result.error) {
|
|
409
|
-
throw new Error(
|
|
494
|
+
throw new Error(`${label} failed to start: ${result.error.message}`)
|
|
410
495
|
}
|
|
411
496
|
if (result.status !== 0) {
|
|
412
|
-
throw new Error(
|
|
413
|
-
'Typecheck failed. Fix the errors above — the agent was not called.',
|
|
414
|
-
)
|
|
497
|
+
throw new Error(failMessage)
|
|
415
498
|
}
|
|
416
|
-
process.stdout.write('Typecheck passed.\n\n')
|
|
417
499
|
}
|
|
418
500
|
|
|
419
501
|
async function typecheckCommandForFiles(cwd, files) {
|
|
@@ -443,9 +525,7 @@ function pickTypecheckCommand(commands) {
|
|
|
443
525
|
)
|
|
444
526
|
if (explicit) return explicit.trim()
|
|
445
527
|
|
|
446
|
-
const other = list.find(
|
|
447
|
-
(command) => !/^\s*"?(?:eslint|stylelint)\b/.test(command),
|
|
448
|
-
)
|
|
528
|
+
const other = list.find((command) => !isLintCommand(command))
|
|
449
529
|
return other ? other.trim() : ''
|
|
450
530
|
}
|
|
451
531
|
|