claude-cli-advanced-starter-pack 1.0.11 → 1.0.13
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 +527 -345
- package/package.json +1 -1
- package/src/commands/init.js +270 -38
- package/src/commands/test-setup.js +7 -6
- package/src/data/releases.json +84 -2
- package/src/testing/config.js +213 -84
- package/src/utils/smart-merge.js +457 -0
- package/src/utils/version-check.js +213 -0
- package/templates/commands/create-task-list.template.md +332 -17
- package/templates/commands/project-impl.template.md +13 -0
- package/templates/commands/update-smart.template.md +111 -0
- package/templates/hooks/ccasp-update-check.template.js +75 -0
- package/templates/hooks/usage-tracking.template.js +222 -0
package/package.json
CHANGED
package/src/commands/init.js
CHANGED
|
@@ -15,6 +15,19 @@ import { fileURLToPath } from 'url';
|
|
|
15
15
|
import { showHeader, showSuccess, showError, showWarning, showInfo } from '../cli/menu.js';
|
|
16
16
|
import { getVersion } from '../utils.js';
|
|
17
17
|
import { createBackup } from './setup-wizard.js';
|
|
18
|
+
import {
|
|
19
|
+
loadUsageTracking,
|
|
20
|
+
getCustomizedUsedAssets,
|
|
21
|
+
isAssetCustomized,
|
|
22
|
+
} from '../utils/version-check.js';
|
|
23
|
+
import {
|
|
24
|
+
getAssetsNeedingMerge,
|
|
25
|
+
compareAssetVersions,
|
|
26
|
+
getLocalAsset,
|
|
27
|
+
getTemplateAsset,
|
|
28
|
+
generateMergeExplanation,
|
|
29
|
+
formatMergeOptions,
|
|
30
|
+
} from '../utils/smart-merge.js';
|
|
18
31
|
|
|
19
32
|
const __filename = fileURLToPath(import.meta.url);
|
|
20
33
|
const __dirname = dirname(__filename);
|
|
@@ -245,6 +258,12 @@ const AVAILABLE_COMMANDS = [
|
|
|
245
258
|
category: 'Maintenance',
|
|
246
259
|
selected: true,
|
|
247
260
|
},
|
|
261
|
+
{
|
|
262
|
+
name: 'update-smart',
|
|
263
|
+
description: 'Smart merge manager for customized assets during updates',
|
|
264
|
+
category: 'Maintenance',
|
|
265
|
+
selected: true,
|
|
266
|
+
},
|
|
248
267
|
];
|
|
249
268
|
|
|
250
269
|
/**
|
|
@@ -471,6 +490,7 @@ Parse the JSON to extract:
|
|
|
471
490
|
- \`updateAvailable\`: Boolean indicating if update exists
|
|
472
491
|
- \`updateHighlights\`: Array of release summaries
|
|
473
492
|
- \`updateFirstDisplayed\`: Whether full highlights have been shown
|
|
493
|
+
- \`projectImplCompleted\`: Whether user has run /project-impl (default: false)
|
|
474
494
|
|
|
475
495
|
### Step 2: Build Dynamic Menu
|
|
476
496
|
|
|
@@ -492,6 +512,16 @@ Set \`updateFirstDisplayed: true\` in ccasp-state.json using Edit tool.
|
|
|
492
512
|
**Subsequent displays** (\`updateAvailable && updateFirstDisplayed\`):
|
|
493
513
|
Show compact banner only.
|
|
494
514
|
|
|
515
|
+
### Step 3b: Show Setup Recommendation (If Applicable)
|
|
516
|
+
|
|
517
|
+
If \`projectImplCompleted\` is \`false\` or missing, display this banner at the BOTTOM of the menu (after the closing box but before the input prompt):
|
|
518
|
+
|
|
519
|
+
\`\`\`
|
|
520
|
+
💡 Tip: Run /project-impl to configure your project (audit CLAUDE.md, detect tech stack, set up deployment)
|
|
521
|
+
\`\`\`
|
|
522
|
+
|
|
523
|
+
This banner should be subtle - just a single line tip. Once the user runs any option in /project-impl, update the state file to set \`projectImplCompleted: true\` and this banner will no longer appear.
|
|
524
|
+
|
|
495
525
|
### Step 4: Display Menu and Wait for Input
|
|
496
526
|
|
|
497
527
|
Ask: "What would you like to do? Enter a key:"
|
|
@@ -1403,7 +1433,7 @@ function loadState() {
|
|
|
1403
1433
|
if (fs.existsSync(statePath)) {
|
|
1404
1434
|
try { return JSON.parse(fs.readFileSync(statePath, 'utf8')); } catch {}
|
|
1405
1435
|
}
|
|
1406
|
-
return { lastCheckTimestamp: 0, updateAvailable: false };
|
|
1436
|
+
return { lastCheckTimestamp: 0, updateAvailable: false, projectImplCompleted: false };
|
|
1407
1437
|
}
|
|
1408
1438
|
|
|
1409
1439
|
function saveState(state) {
|
|
@@ -1471,7 +1501,7 @@ module.exports = async function ccaspUpdateCheck(context) {
|
|
|
1471
1501
|
}
|
|
1472
1502
|
|
|
1473
1503
|
/**
|
|
1474
|
-
* Generate settings.json with CCASP update check hook
|
|
1504
|
+
* Generate settings.json with CCASP update check hook and usage tracking
|
|
1475
1505
|
*/
|
|
1476
1506
|
function generateSettingsJson(projectName) {
|
|
1477
1507
|
return JSON.stringify({
|
|
@@ -1491,6 +1521,17 @@ function generateSettingsJson(projectName) {
|
|
|
1491
1521
|
}
|
|
1492
1522
|
]
|
|
1493
1523
|
}
|
|
1524
|
+
],
|
|
1525
|
+
"PostToolUse": [
|
|
1526
|
+
{
|
|
1527
|
+
"matcher": "Skill|Read",
|
|
1528
|
+
"hooks": [
|
|
1529
|
+
{
|
|
1530
|
+
"type": "command",
|
|
1531
|
+
"command": "node .claude/hooks/usage-tracking.js"
|
|
1532
|
+
}
|
|
1533
|
+
]
|
|
1534
|
+
}
|
|
1494
1535
|
]
|
|
1495
1536
|
}
|
|
1496
1537
|
}, null, 2);
|
|
@@ -1727,6 +1768,19 @@ export async function runInit(options = {}) {
|
|
|
1727
1768
|
console.log(chalk.blue(' ○ hooks/ccasp-update-check.js exists (preserved)'));
|
|
1728
1769
|
}
|
|
1729
1770
|
|
|
1771
|
+
// Deploy the usage tracking hook (tracks command/skill/agent usage for smart merge)
|
|
1772
|
+
const usageTrackingHookPath = join(hooksDir, 'usage-tracking.js');
|
|
1773
|
+
if (!existsSync(usageTrackingHookPath)) {
|
|
1774
|
+
const templatePath = join(__dirname, '..', '..', 'templates', 'hooks', 'usage-tracking.template.js');
|
|
1775
|
+
if (existsSync(templatePath)) {
|
|
1776
|
+
const hookContent = readFileSync(templatePath, 'utf8');
|
|
1777
|
+
writeFileSync(usageTrackingHookPath, hookContent, 'utf8');
|
|
1778
|
+
console.log(chalk.green(' ✓ Created hooks/usage-tracking.js (smart merge tracking)'));
|
|
1779
|
+
}
|
|
1780
|
+
} else {
|
|
1781
|
+
console.log(chalk.blue(' ○ hooks/usage-tracking.js exists (preserved)'));
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1730
1784
|
console.log('');
|
|
1731
1785
|
|
|
1732
1786
|
// Step 4: Select optional features
|
|
@@ -1838,53 +1892,226 @@ export async function runInit(options = {}) {
|
|
|
1838
1892
|
// Step 6: Check for existing commands that would be overwritten
|
|
1839
1893
|
const commandsToOverwrite = finalCommands.filter(cmd => existingCmdNames.includes(cmd));
|
|
1840
1894
|
|
|
1895
|
+
// Track commands that need smart merge handling
|
|
1896
|
+
const smartMergeDecisions = {};
|
|
1897
|
+
|
|
1841
1898
|
let overwrite = options.force || false;
|
|
1842
1899
|
if (commandsToOverwrite.length > 0 && !overwrite) {
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1900
|
+
// Check for customized assets that have been used
|
|
1901
|
+
const assetsNeedingMerge = getAssetsNeedingMerge(process.cwd());
|
|
1902
|
+
const customizedCommands = commandsToOverwrite.filter(cmd =>
|
|
1903
|
+
assetsNeedingMerge.commands?.some(a => a.name === cmd)
|
|
1904
|
+
);
|
|
1905
|
+
|
|
1906
|
+
// Show smart merge prompt for customized commands
|
|
1907
|
+
if (customizedCommands.length > 0) {
|
|
1908
|
+
console.log(chalk.cyan.bold('\n 🔀 Smart Merge Available'));
|
|
1909
|
+
console.log(chalk.dim(' The following commands have been customized and used:\n'));
|
|
1910
|
+
|
|
1911
|
+
for (const cmd of customizedCommands) {
|
|
1912
|
+
const assetInfo = assetsNeedingMerge.commands.find(a => a.name === cmd);
|
|
1913
|
+
console.log(chalk.cyan(` • /${cmd}`));
|
|
1914
|
+
console.log(chalk.dim(` Used ${assetInfo.usageData.useCount} time(s), last: ${new Date(assetInfo.usageData.lastUsed).toLocaleDateString()}`));
|
|
1915
|
+
console.log(chalk.dim(` Change: ${assetInfo.comparison.significance.level} significance - ${assetInfo.comparison.summary}`));
|
|
1916
|
+
}
|
|
1917
|
+
console.log('');
|
|
1848
1918
|
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1919
|
+
const { smartMergeAction } = await inquirer.prompt([
|
|
1920
|
+
{
|
|
1921
|
+
type: 'list',
|
|
1922
|
+
name: 'smartMergeAction',
|
|
1923
|
+
message: 'How would you like to handle your customized commands?',
|
|
1924
|
+
choices: [
|
|
1925
|
+
{ name: '🔍 Explore each one - Let Claude explain the changes', value: 'explore' },
|
|
1926
|
+
{ name: '📋 Skip all customized - Keep your versions', value: 'skip-customized' },
|
|
1927
|
+
{ name: '🔄 Replace all - Use new versions (lose customizations)', value: 'replace-all' },
|
|
1928
|
+
{ name: '❌ Cancel installation', value: 'cancel' },
|
|
1929
|
+
],
|
|
1930
|
+
},
|
|
1931
|
+
]);
|
|
1932
|
+
|
|
1933
|
+
if (smartMergeAction === 'cancel') {
|
|
1934
|
+
console.log(chalk.dim('\nCancelled. No changes made.'));
|
|
1935
|
+
return;
|
|
1936
|
+
}
|
|
1862
1937
|
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1938
|
+
if (smartMergeAction === 'explore') {
|
|
1939
|
+
// Individual exploration for each customized command
|
|
1940
|
+
console.log(chalk.cyan('\n Exploring customized commands...\n'));
|
|
1941
|
+
|
|
1942
|
+
for (const cmd of customizedCommands) {
|
|
1943
|
+
const assetInfo = assetsNeedingMerge.commands.find(a => a.name === cmd);
|
|
1944
|
+
const local = getLocalAsset('commands', cmd, process.cwd());
|
|
1945
|
+
const template = getTemplateAsset('commands', cmd);
|
|
1946
|
+
|
|
1947
|
+
// Show merge explanation
|
|
1948
|
+
console.log(chalk.bold(`\n ┌${'─'.repeat(60)}┐`));
|
|
1949
|
+
console.log(chalk.bold(` │ /${cmd.padEnd(58)} │`));
|
|
1950
|
+
console.log(chalk.bold(` └${'─'.repeat(60)}┘`));
|
|
1951
|
+
|
|
1952
|
+
const explanation = generateMergeExplanation(
|
|
1953
|
+
'commands',
|
|
1954
|
+
cmd,
|
|
1955
|
+
assetInfo.comparison,
|
|
1956
|
+
local?.content,
|
|
1957
|
+
template?.content
|
|
1958
|
+
);
|
|
1959
|
+
|
|
1960
|
+
// Display condensed explanation
|
|
1961
|
+
console.log(chalk.dim('\n ' + explanation.split('\n').slice(0, 15).join('\n ')));
|
|
1962
|
+
|
|
1963
|
+
const { decision } = await inquirer.prompt([
|
|
1964
|
+
{
|
|
1965
|
+
type: 'list',
|
|
1966
|
+
name: 'decision',
|
|
1967
|
+
message: `What would you like to do with /${cmd}?`,
|
|
1968
|
+
choices: [
|
|
1969
|
+
{ name: 'Skip - Keep your customized version', value: 'skip' },
|
|
1970
|
+
{ name: 'Backup & Replace - Save yours, use new version', value: 'backup' },
|
|
1971
|
+
{ name: 'Replace - Use new version (no backup)', value: 'replace' },
|
|
1972
|
+
{ name: 'Show full diff', value: 'diff' },
|
|
1973
|
+
],
|
|
1974
|
+
},
|
|
1975
|
+
]);
|
|
1976
|
+
|
|
1977
|
+
if (decision === 'diff') {
|
|
1978
|
+
// Show full diff
|
|
1979
|
+
console.log(chalk.dim('\n--- Your Version ---'));
|
|
1980
|
+
console.log(local?.content?.slice(0, 500) + (local?.content?.length > 500 ? '\n...(truncated)' : ''));
|
|
1981
|
+
console.log(chalk.dim('\n--- Update Version ---'));
|
|
1982
|
+
console.log(template?.content?.slice(0, 500) + (template?.content?.length > 500 ? '\n...(truncated)' : ''));
|
|
1983
|
+
|
|
1984
|
+
// Re-prompt after showing diff
|
|
1985
|
+
const { finalDecision } = await inquirer.prompt([
|
|
1986
|
+
{
|
|
1987
|
+
type: 'list',
|
|
1988
|
+
name: 'finalDecision',
|
|
1989
|
+
message: `Final decision for /${cmd}?`,
|
|
1990
|
+
choices: [
|
|
1991
|
+
{ name: 'Skip - Keep your version', value: 'skip' },
|
|
1992
|
+
{ name: 'Backup & Replace', value: 'backup' },
|
|
1993
|
+
{ name: 'Replace without backup', value: 'replace' },
|
|
1994
|
+
],
|
|
1995
|
+
},
|
|
1996
|
+
]);
|
|
1997
|
+
smartMergeDecisions[cmd] = finalDecision;
|
|
1998
|
+
} else {
|
|
1999
|
+
smartMergeDecisions[cmd] = decision;
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
} else if (smartMergeAction === 'skip-customized') {
|
|
2003
|
+
// Mark all customized commands as skip
|
|
2004
|
+
for (const cmd of customizedCommands) {
|
|
2005
|
+
smartMergeDecisions[cmd] = 'skip';
|
|
2006
|
+
}
|
|
2007
|
+
console.log(chalk.green(`\n ✓ Will preserve ${customizedCommands.length} customized command(s)`));
|
|
2008
|
+
} else if (smartMergeAction === 'replace-all') {
|
|
2009
|
+
// Mark all customized commands as replace with backup
|
|
2010
|
+
for (const cmd of customizedCommands) {
|
|
2011
|
+
smartMergeDecisions[cmd] = 'backup';
|
|
2012
|
+
}
|
|
2013
|
+
console.log(chalk.yellow(`\n ⚠ Will backup and replace ${customizedCommands.length} customized command(s)`));
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
// Remove customized commands from the standard overwrite flow
|
|
2017
|
+
// (they're handled by smart merge decisions)
|
|
2018
|
+
const nonCustomizedToOverwrite = commandsToOverwrite.filter(c => !customizedCommands.includes(c));
|
|
2019
|
+
|
|
2020
|
+
if (nonCustomizedToOverwrite.length > 0) {
|
|
2021
|
+
console.log(chalk.yellow.bold('\n ⚠ The following non-customized commands also exist:'));
|
|
2022
|
+
for (const cmd of nonCustomizedToOverwrite) {
|
|
2023
|
+
console.log(chalk.yellow(` • /${cmd}`));
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
1866
2026
|
}
|
|
1867
2027
|
|
|
1868
|
-
|
|
1869
|
-
const
|
|
1870
|
-
|
|
1871
|
-
if (
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
console.log(
|
|
1879
|
-
|
|
1880
|
-
|
|
2028
|
+
// Standard overwrite prompt for non-customized commands
|
|
2029
|
+
const remainingToOverwrite = commandsToOverwrite.filter(c => !smartMergeDecisions[c]);
|
|
2030
|
+
|
|
2031
|
+
if (remainingToOverwrite.length > 0) {
|
|
2032
|
+
if (!customizedCommands || customizedCommands.length === 0) {
|
|
2033
|
+
console.log(chalk.yellow.bold(' ⚠ The following commands already exist:'));
|
|
2034
|
+
for (const cmd of remainingToOverwrite) {
|
|
2035
|
+
console.log(chalk.yellow(` • /${cmd}`));
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
console.log('');
|
|
2039
|
+
|
|
2040
|
+
const { overwriteChoice } = await inquirer.prompt([
|
|
2041
|
+
{
|
|
2042
|
+
type: 'list',
|
|
2043
|
+
name: 'overwriteChoice',
|
|
2044
|
+
message: 'How would you like to handle these existing commands?',
|
|
2045
|
+
choices: [
|
|
2046
|
+
{ name: 'Skip existing - only install new commands (recommended)', value: 'skip' },
|
|
2047
|
+
{ name: 'Overwrite with backup - save existing to .claude/backups/ first', value: 'backup' },
|
|
2048
|
+
{ name: 'Overwrite all - replace existing (no backup)', value: 'overwrite' },
|
|
2049
|
+
{ name: 'Cancel installation', value: 'cancel' },
|
|
2050
|
+
],
|
|
2051
|
+
},
|
|
2052
|
+
]);
|
|
2053
|
+
|
|
2054
|
+
if (overwriteChoice === 'cancel') {
|
|
2055
|
+
console.log(chalk.dim('\nCancelled. No changes made.'));
|
|
2056
|
+
return;
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
overwrite = overwriteChoice === 'overwrite' || overwriteChoice === 'backup';
|
|
2060
|
+
|
|
2061
|
+
// Apply decision to remaining commands
|
|
2062
|
+
for (const cmd of remainingToOverwrite) {
|
|
2063
|
+
smartMergeDecisions[cmd] = overwriteChoice === 'skip' ? 'skip' : (overwriteChoice === 'backup' ? 'backup' : 'replace');
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
if (!overwrite) {
|
|
2067
|
+
// Filter out skipped commands
|
|
2068
|
+
const skippedCommands = Object.entries(smartMergeDecisions)
|
|
2069
|
+
.filter(([, decision]) => decision === 'skip')
|
|
2070
|
+
.map(([cmd]) => cmd);
|
|
2071
|
+
const filtered = finalCommands.filter((c) => !skippedCommands.includes(c) || requiredCommands.includes(c));
|
|
2072
|
+
finalCommands.length = 0;
|
|
2073
|
+
finalCommands.push(...filtered);
|
|
2074
|
+
console.log(chalk.green(`\n ✓ Will install ${finalCommands.length} new command(s), preserving ${skippedCommands.length} existing`));
|
|
2075
|
+
} else if (overwriteChoice === 'backup') {
|
|
2076
|
+
console.log(chalk.cyan(`\n ✓ Will backup and overwrite ${remainingToOverwrite.length} existing command(s)`));
|
|
2077
|
+
} else {
|
|
2078
|
+
console.log(chalk.yellow(`\n ⚠ Will overwrite ${remainingToOverwrite.length} existing command(s)`));
|
|
2079
|
+
}
|
|
2080
|
+
} else if (Object.keys(smartMergeDecisions).length > 0) {
|
|
2081
|
+
// All commands handled by smart merge
|
|
2082
|
+
const skippedCommands = Object.entries(smartMergeDecisions)
|
|
2083
|
+
.filter(([, decision]) => decision === 'skip')
|
|
2084
|
+
.map(([cmd]) => cmd);
|
|
2085
|
+
|
|
2086
|
+
if (skippedCommands.length > 0) {
|
|
2087
|
+
const filtered = finalCommands.filter((c) => !skippedCommands.includes(c) || requiredCommands.includes(c));
|
|
2088
|
+
finalCommands.length = 0;
|
|
2089
|
+
finalCommands.push(...filtered);
|
|
2090
|
+
}
|
|
1881
2091
|
}
|
|
1882
2092
|
}
|
|
1883
2093
|
|
|
1884
2094
|
// Track if we should create backups (set outside the if block for use later)
|
|
2095
|
+
// Now also considers smart merge decisions
|
|
1885
2096
|
const createBackups = options.backup || (typeof overwrite !== 'undefined' && commandsToOverwrite.length > 0 && !options.force);
|
|
1886
2097
|
let backedUpFiles = [];
|
|
1887
2098
|
|
|
2099
|
+
// Helper to check if a command should be backed up based on smart merge decisions
|
|
2100
|
+
const shouldBackupCommand = (cmdName) => {
|
|
2101
|
+
if (smartMergeDecisions[cmdName]) {
|
|
2102
|
+
return smartMergeDecisions[cmdName] === 'backup';
|
|
2103
|
+
}
|
|
2104
|
+
return createBackups;
|
|
2105
|
+
};
|
|
2106
|
+
|
|
2107
|
+
// Helper to check if a command should be skipped based on smart merge decisions
|
|
2108
|
+
const shouldSkipCommand = (cmdName) => {
|
|
2109
|
+
if (smartMergeDecisions[cmdName]) {
|
|
2110
|
+
return smartMergeDecisions[cmdName] === 'skip';
|
|
2111
|
+
}
|
|
2112
|
+
return false;
|
|
2113
|
+
};
|
|
2114
|
+
|
|
1888
2115
|
// Step 7: Install commands
|
|
1889
2116
|
console.log(chalk.bold('Step 6: Installing slash commands\n'));
|
|
1890
2117
|
|
|
@@ -1905,6 +2132,11 @@ export async function runInit(options = {}) {
|
|
|
1905
2132
|
|
|
1906
2133
|
for (const cmdName of finalCommands) {
|
|
1907
2134
|
try {
|
|
2135
|
+
// Skip commands that were marked to skip in smart merge
|
|
2136
|
+
if (shouldSkipCommand(cmdName)) {
|
|
2137
|
+
continue;
|
|
2138
|
+
}
|
|
2139
|
+
|
|
1908
2140
|
const cmdPath = join(commandsDir, `${cmdName}.md`);
|
|
1909
2141
|
|
|
1910
2142
|
let content;
|
|
@@ -1927,8 +2159,8 @@ export async function runInit(options = {}) {
|
|
|
1927
2159
|
}
|
|
1928
2160
|
}
|
|
1929
2161
|
|
|
1930
|
-
// Create backup if overwriting existing file
|
|
1931
|
-
if (existsSync(cmdPath) &&
|
|
2162
|
+
// Create backup if overwriting existing file (respects smart merge decisions)
|
|
2163
|
+
if (existsSync(cmdPath) && shouldBackupCommand(cmdName)) {
|
|
1932
2164
|
const backupPath = createBackup(cmdPath);
|
|
1933
2165
|
if (backupPath) {
|
|
1934
2166
|
backedUpFiles.push({ original: cmdPath, backup: backupPath });
|
|
@@ -243,8 +243,8 @@ export async function runTestSetup(options) {
|
|
|
243
243
|
console.log(chalk.dim(` export ${passwordVar}="your_password"`));
|
|
244
244
|
}
|
|
245
245
|
} else if (credentialSource === 'config') {
|
|
246
|
-
showWarning('
|
|
247
|
-
console.log(chalk.dim('
|
|
246
|
+
showWarning('Storing credentials in config is not recommended for security.');
|
|
247
|
+
console.log(chalk.dim('Consider using environment variables instead.'));
|
|
248
248
|
console.log('');
|
|
249
249
|
|
|
250
250
|
const { username, password } = await inquirer.prompt([
|
|
@@ -398,9 +398,9 @@ export async function runTestSetup(options) {
|
|
|
398
398
|
|
|
399
399
|
const testingConfig = createTestingConfig(config);
|
|
400
400
|
|
|
401
|
-
// Save main config
|
|
401
|
+
// Save main config to tech-stack.json
|
|
402
402
|
const configPath = saveTestingConfig(testingConfig);
|
|
403
|
-
spinner.text = 'Saved testing.json';
|
|
403
|
+
spinner.text = 'Saved testing config to tech-stack.json';
|
|
404
404
|
|
|
405
405
|
// Save testing rules markdown
|
|
406
406
|
const { generateRules } = await inquirer.prompt([
|
|
@@ -415,7 +415,7 @@ export async function runTestSetup(options) {
|
|
|
415
415
|
let rulesPath = null;
|
|
416
416
|
if (generateRules) {
|
|
417
417
|
rulesPath = saveTestingRules(testingConfig);
|
|
418
|
-
spinner.text = 'Saved TESTING_RULES.md';
|
|
418
|
+
spinner.text = 'Saved TESTING_RULES.md to .claude/task-lists/';
|
|
419
419
|
}
|
|
420
420
|
|
|
421
421
|
spinner.succeed('Configuration files created');
|
|
@@ -427,7 +427,8 @@ export async function runTestSetup(options) {
|
|
|
427
427
|
`Credentials: ${CREDENTIAL_SOURCES[config.credentialSource].name}`,
|
|
428
428
|
`Playwright: ${config.playwrightEnabled ? 'Enabled' : 'Disabled'}`,
|
|
429
429
|
'',
|
|
430
|
-
`Config: ${configPath}`,
|
|
430
|
+
`Config saved to: ${configPath}`,
|
|
431
|
+
'Testing config is now stored in tech-stack.json under the "testing" section.',
|
|
431
432
|
];
|
|
432
433
|
|
|
433
434
|
if (rulesPath) {
|
package/src/data/releases.json
CHANGED
|
@@ -1,10 +1,78 @@
|
|
|
1
1
|
{
|
|
2
2
|
"releases": [
|
|
3
|
+
{
|
|
4
|
+
"version": "1.0.13",
|
|
5
|
+
"date": "2026-01-30",
|
|
6
|
+
"summary": "Feature: Smart Update Merge Tracking - Intelligent handling of customized assets during updates",
|
|
7
|
+
"highlights": [
|
|
8
|
+
"Tracks usage of commands, skills, agents, and hooks in usage-tracking.json",
|
|
9
|
+
"Smart merge detection: identifies customized assets that have updates available",
|
|
10
|
+
"Interactive merge exploration: Claude explains what changes, offers merge/replace/skip options",
|
|
11
|
+
"New /update-smart command for manual merge exploration",
|
|
12
|
+
"Usage tracking hook runs on PostToolUse for Skill and Read tools"
|
|
13
|
+
],
|
|
14
|
+
"newFeatures": {
|
|
15
|
+
"commands": [
|
|
16
|
+
{
|
|
17
|
+
"name": "update-smart",
|
|
18
|
+
"description": "Smart merge manager for customized assets during updates",
|
|
19
|
+
"category": "Maintenance"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"agents": [],
|
|
23
|
+
"skills": [],
|
|
24
|
+
"hooks": [
|
|
25
|
+
{
|
|
26
|
+
"name": "usage-tracking",
|
|
27
|
+
"description": "Tracks usage of commands, skills, agents for smart merge detection"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"other": [
|
|
31
|
+
{
|
|
32
|
+
"name": "smart-merge-system",
|
|
33
|
+
"description": "Intelligent diff comparison and merge exploration for customized assets"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "usage-tracking-json",
|
|
37
|
+
"description": "Persistent tracking of asset usage in .claude/config/usage-tracking.json"
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"breaking": [],
|
|
42
|
+
"deprecated": []
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"version": "1.0.12",
|
|
46
|
+
"date": "2026-01-30",
|
|
47
|
+
"summary": "Feature: /project-impl recommendation banner in /menu",
|
|
48
|
+
"highlights": [
|
|
49
|
+
"Shows setup tip when /project-impl hasn't been run yet",
|
|
50
|
+
"Tracks projectImplCompleted state in ccasp-state.json",
|
|
51
|
+
"Banner disappears after running any /project-impl option"
|
|
52
|
+
],
|
|
53
|
+
"newFeatures": {
|
|
54
|
+
"commands": [],
|
|
55
|
+
"agents": [],
|
|
56
|
+
"skills": [],
|
|
57
|
+
"hooks": [],
|
|
58
|
+
"other": [
|
|
59
|
+
{
|
|
60
|
+
"name": "project-impl-banner",
|
|
61
|
+
"description": "Recommends running /project-impl for new installations"
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
"breaking": [],
|
|
66
|
+
"deprecated": []
|
|
67
|
+
},
|
|
3
68
|
{
|
|
4
69
|
"version": "1.0.11",
|
|
5
70
|
"date": "2026-01-30",
|
|
6
|
-
"summary": "
|
|
7
|
-
"highlights": [
|
|
71
|
+
"summary": "Security: Removed project-specific example text from prompts",
|
|
72
|
+
"highlights": [
|
|
73
|
+
"Changed ngrok example from 'my.app.benefits360' to 'my-app-name'",
|
|
74
|
+
"Security audit confirmed no personal data in npm package"
|
|
75
|
+
],
|
|
8
76
|
"newFeatures": {
|
|
9
77
|
"commands": [],
|
|
10
78
|
"agents": [],
|
|
@@ -398,6 +466,20 @@
|
|
|
398
466
|
"update-check": {
|
|
399
467
|
"addedIn": "1.0.5",
|
|
400
468
|
"required": false
|
|
469
|
+
},
|
|
470
|
+
"update-smart": {
|
|
471
|
+
"addedIn": "1.0.13",
|
|
472
|
+
"required": false
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
"hooks": {
|
|
476
|
+
"ccasp-update-check": {
|
|
477
|
+
"addedIn": "1.0.7",
|
|
478
|
+
"required": true
|
|
479
|
+
},
|
|
480
|
+
"usage-tracking": {
|
|
481
|
+
"addedIn": "1.0.13",
|
|
482
|
+
"required": false
|
|
401
483
|
}
|
|
402
484
|
},
|
|
403
485
|
"optionalFeatures": {
|