@nitra/cursor 3.21.0 → 3.21.1
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/CHANGELOG.md +7 -0
- package/bin/n-cursor.js +112 -52
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.21.1] - 2026-06-04
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- CLI sync: ховати блоки правил / 🧩 Skills / ⌨️ Commands / 🥧 Pi skills (рядки ⬇ і підсумок) за успішного прогону — друкувати лише коли fail > 0 (helper captureOutput)
|
|
8
|
+
- CLI sync: ховати post-sync рядки (📝 setup-bun-deps action / 📝 AGENTS.md / 📝 CLAUDE.md / 🤖 Claude-конфіг) за успішного прогону — через captureOutput, друк лише при помилці
|
|
9
|
+
|
|
3
10
|
## [3.21.0] - 2026-06-04
|
|
4
11
|
|
|
5
12
|
### Added
|
package/bin/n-cursor.js
CHANGED
|
@@ -1132,6 +1132,48 @@ async function runSyncStep(prefix, action) {
|
|
|
1132
1132
|
}
|
|
1133
1133
|
}
|
|
1134
1134
|
|
|
1135
|
+
/**
|
|
1136
|
+
* Виконує `action`, буферизуючи весь його stdout/console-вивід.
|
|
1137
|
+
*
|
|
1138
|
+
* Мотивація: за успішного прогону sync-блоку рядки `⬇ … ✅` і підсумок
|
|
1139
|
+
* (`🧩 Skills: N скопійовано, 0 з помилками`) не несуть користі й лише
|
|
1140
|
+
* захаращують термінал. Тому буфер скидається в реальний stdout **лише**
|
|
1141
|
+
* коли крок повернув `fail > 0` (або кинув виняток); за `fail === 0` —
|
|
1142
|
+
* відкидається мовчки.
|
|
1143
|
+
*
|
|
1144
|
+
* @template T
|
|
1145
|
+
* @param {() => Promise<T>} action крок синку, що повертає обʼєкт із лічильником помилок `fail`
|
|
1146
|
+
* @returns {Promise<T>} результат `action` без змін
|
|
1147
|
+
*/
|
|
1148
|
+
async function captureOutput(action) {
|
|
1149
|
+
const buffer = []
|
|
1150
|
+
const realStdoutWrite = process.stdout.write
|
|
1151
|
+
const realLog = console.log
|
|
1152
|
+
const realError = console.error
|
|
1153
|
+
const flush = () => realStdoutWrite.call(process.stdout, buffer.join(''))
|
|
1154
|
+
process.stdout.write = (...args) => {
|
|
1155
|
+
const [chunk] = args
|
|
1156
|
+
buffer.push(typeof chunk === 'string' ? chunk : chunk.toString())
|
|
1157
|
+
const cb = args.find((arg) => typeof arg === 'function')
|
|
1158
|
+
if (cb) cb()
|
|
1159
|
+
return true
|
|
1160
|
+
}
|
|
1161
|
+
console.log = (...args) => buffer.push(`${args.map(String).join(' ')}\n`)
|
|
1162
|
+
console.error = (...args) => buffer.push(`${args.map(String).join(' ')}\n`)
|
|
1163
|
+
try {
|
|
1164
|
+
const result = await action()
|
|
1165
|
+
if (result?.fail > 0) flush()
|
|
1166
|
+
return result
|
|
1167
|
+
} catch (error) {
|
|
1168
|
+
flush()
|
|
1169
|
+
throw error
|
|
1170
|
+
} finally {
|
|
1171
|
+
process.stdout.write = realStdoutWrite
|
|
1172
|
+
console.log = realLog
|
|
1173
|
+
console.error = realError
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1135
1177
|
/**
|
|
1136
1178
|
* Копіює керовані `.mdc` файли з пакету до `.cursor/rules`.
|
|
1137
1179
|
* @param {string[]} rules список rules з конфігу
|
|
@@ -1357,14 +1399,19 @@ async function runSync() {
|
|
|
1357
1399
|
console.log(`📋 Правил до завантаження: ${rules.length}`)
|
|
1358
1400
|
console.log(`📋 Skills до синхронізації: ${skills.length}`)
|
|
1359
1401
|
|
|
1360
|
-
await runSyncStep('❌ Не вдалося записати setup-bun-deps action: ',
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1402
|
+
await runSyncStep('❌ Не вдалося записати setup-bun-deps action: ', () =>
|
|
1403
|
+
captureOutput(async () => {
|
|
1404
|
+
const { destPath } = await syncSetupBunDepsAction(cwd(), effectivePackageRoot)
|
|
1405
|
+
console.log(`📝 Оновлено ${destPath} (composite setup-bun-deps з пакету)\n`)
|
|
1406
|
+
})
|
|
1407
|
+
)
|
|
1364
1408
|
|
|
1365
1409
|
const rulesDir = join(cwd(), RULES_DIR)
|
|
1366
1410
|
await mkdir(rulesDir, { recursive: true })
|
|
1367
|
-
const { successCount, failCount } = await
|
|
1411
|
+
const { successCount, failCount } = await captureOutput(async () => {
|
|
1412
|
+
const stats = await syncManagedRuleFiles(rules, bundledRulesDir, rulesDir)
|
|
1413
|
+
return { ...stats, fail: stats.failCount }
|
|
1414
|
+
})
|
|
1368
1415
|
|
|
1369
1416
|
await runSyncStep(`❌ Не вдалося прибрати зайві файли в ${RULES_DIR}: `, async () => {
|
|
1370
1417
|
const removed = await removeOrphanManagedRuleFiles(rulesDir, rules)
|
|
@@ -1372,10 +1419,13 @@ async function runSync() {
|
|
|
1372
1419
|
})
|
|
1373
1420
|
|
|
1374
1421
|
await runSyncStep('❌ Skills: ', async () => {
|
|
1375
|
-
const {
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1422
|
+
const { fail: skillFail } = await captureOutput(async () => {
|
|
1423
|
+
const { success: skillOk, fail } = await syncSkills(skills, bundledSkillsDir)
|
|
1424
|
+
if (skills.length > 0) {
|
|
1425
|
+
console.log(`\n🧩 Skills: ${skillOk} скопійовано, ${fail} з помилками`)
|
|
1426
|
+
}
|
|
1427
|
+
return { fail }
|
|
1428
|
+
})
|
|
1379
1429
|
const removedSkills = await removeOrphanManagedSkillDirs(join(cwd(), SKILLS_DIR), skills)
|
|
1380
1430
|
logRemovedManagedItems('skills', SKILLS_DIR, removedSkills)
|
|
1381
1431
|
if (skillFail > 0) {
|
|
@@ -1384,13 +1434,16 @@ async function runSync() {
|
|
|
1384
1434
|
})
|
|
1385
1435
|
|
|
1386
1436
|
await runSyncStep('❌ Commands: ', async () => {
|
|
1387
|
-
const {
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1437
|
+
const { fail: totalFail } = await captureOutput(async () => {
|
|
1438
|
+
const { success: cmdOk, fail: cmdFail } = await syncCommands(skills, bundledSkillsDir)
|
|
1439
|
+
const { success: localOk, fail: localFail } = await syncLocalOnlySkillCommands(skills)
|
|
1440
|
+
const totalOk = cmdOk + localOk
|
|
1441
|
+
const fail = cmdFail + localFail
|
|
1442
|
+
if (totalOk + fail > 0) {
|
|
1443
|
+
console.log(`\n⌨️ Commands: ${totalOk} скопійовано, ${fail} з помилками`)
|
|
1444
|
+
}
|
|
1445
|
+
return { fail }
|
|
1446
|
+
})
|
|
1394
1447
|
const commandsDir = join(cwd(), COMMANDS_DIR)
|
|
1395
1448
|
const removedCmds = await removeOrphanManagedCommandFiles(commandsDir, skills)
|
|
1396
1449
|
logRemovedManagedItems('commands', COMMANDS_DIR, removedCmds)
|
|
@@ -1402,13 +1455,16 @@ async function runSync() {
|
|
|
1402
1455
|
})
|
|
1403
1456
|
|
|
1404
1457
|
await runSyncStep('❌ Pi skills: ', async () => {
|
|
1405
|
-
const {
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1458
|
+
const { fail: totalFail } = await captureOutput(async () => {
|
|
1459
|
+
const { success: piOk, fail: piFail } = await syncPiSkills(skills, bundledSkillsDir)
|
|
1460
|
+
const { success: piLocalOk, fail: piLocalFail } = await syncLocalOnlyPiSkills(skills)
|
|
1461
|
+
const totalOk = piOk + piLocalOk
|
|
1462
|
+
const fail = piFail + piLocalFail
|
|
1463
|
+
if (totalOk + fail > 0) {
|
|
1464
|
+
console.log(`\n🥧 Pi skills: ${totalOk} скопійовано, ${fail} з помилками`)
|
|
1465
|
+
}
|
|
1466
|
+
return { fail }
|
|
1467
|
+
})
|
|
1412
1468
|
const piSkillsDir = join(cwd(), PI_SKILLS_DIR)
|
|
1413
1469
|
const removedPi = await removeOrphanManagedPiSkillDirs(piSkillsDir, skills)
|
|
1414
1470
|
logRemovedManagedItems('pi skills', PI_SKILLS_DIR, removedPi)
|
|
@@ -1419,39 +1475,43 @@ async function runSync() {
|
|
|
1419
1475
|
}
|
|
1420
1476
|
})
|
|
1421
1477
|
|
|
1422
|
-
await runSyncStep(`❌ Не вдалося оновити ${AGENTS_FILE}: `, () =>
|
|
1478
|
+
await runSyncStep(`❌ Не вдалося оновити ${AGENTS_FILE}: `, () =>
|
|
1479
|
+
captureOutput(() => syncAgentsMd(bundledAgentsTemplatePath))
|
|
1480
|
+
)
|
|
1423
1481
|
await runSyncStep('❌ Не вдалося оновити CLAUDE.md: ', () =>
|
|
1424
|
-
syncClaudeMd(/** @type {string[] | undefined} */ (ignore))
|
|
1482
|
+
captureOutput(() => syncClaudeMd(/** @type {string[] | undefined} */ (ignore)))
|
|
1425
1483
|
)
|
|
1426
1484
|
|
|
1427
|
-
await runSyncStep('❌ Не вдалося синхронізувати Claude-конфіг: ',
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
const parts = []
|
|
1439
|
-
if (result.settings) parts.push('.claude/settings.json')
|
|
1440
|
-
if (result.cursorHooks) parts.push('.cursor/hooks.json')
|
|
1441
|
-
if (result.commands.length > 0) parts.push(`${result.commands.length} slash-commands`)
|
|
1442
|
-
if (result.adrHook) parts.push('.claude/hooks/capture-decisions.sh')
|
|
1443
|
-
if (result.adrNormalizeHook) parts.push('.claude/hooks/normalize-decisions.sh')
|
|
1444
|
-
if (result.adrHookLib?.length > 0) {
|
|
1445
|
-
for (const libPath of result.adrHookLib) {
|
|
1446
|
-
parts.push(libPath)
|
|
1485
|
+
await runSyncStep('❌ Не вдалося синхронізувати Claude-конфіг: ', () =>
|
|
1486
|
+
captureOutput(async () => {
|
|
1487
|
+
const result = await syncClaudeConfig({
|
|
1488
|
+
projectRoot: cwd(),
|
|
1489
|
+
bundledPackageRoot: effectivePackageRoot,
|
|
1490
|
+
enabled: claudeConfigEnabled,
|
|
1491
|
+
rules
|
|
1492
|
+
})
|
|
1493
|
+
if (!claudeConfigEnabled) {
|
|
1494
|
+
console.log('🤖 Claude-конфіг: пропущено (claude-config: false у .n-cursor.json)')
|
|
1495
|
+
return
|
|
1447
1496
|
}
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1497
|
+
const parts = []
|
|
1498
|
+
if (result.settings) parts.push('.claude/settings.json')
|
|
1499
|
+
if (result.cursorHooks) parts.push('.cursor/hooks.json')
|
|
1500
|
+
if (result.commands.length > 0) parts.push(`${result.commands.length} slash-commands`)
|
|
1501
|
+
if (result.adrHook) parts.push('.claude/hooks/capture-decisions.sh')
|
|
1502
|
+
if (result.adrNormalizeHook) parts.push('.claude/hooks/normalize-decisions.sh')
|
|
1503
|
+
if (result.adrHookLib?.length > 0) {
|
|
1504
|
+
for (const libPath of result.adrHookLib) {
|
|
1505
|
+
parts.push(libPath)
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
if (result.gitignoreAdr) parts.push('.gitignore (adr fragment)')
|
|
1509
|
+
if (result.piExtension) parts.push('.pi/extensions/n-cursor-adr/')
|
|
1510
|
+
if (parts.length > 0) {
|
|
1511
|
+
console.log(`🤖 Claude-конфіг: ${parts.join(', ')}`)
|
|
1512
|
+
}
|
|
1513
|
+
})
|
|
1514
|
+
)
|
|
1455
1515
|
|
|
1456
1516
|
await runSyncStep('❌ Не вдалося оновити .gitignore (worktree): ', async () => {
|
|
1457
1517
|
const { written } = await syncGitignoreWorktree(cwd())
|