claude-cli-advanced-starter-pack 1.0.12 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-cli-advanced-starter-pack",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "Advanced Claude Code CLI toolkit - agents, hooks, skills, MCP servers, phased development, and GitHub integration",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -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
  /**
@@ -1482,7 +1501,7 @@ module.exports = async function ccaspUpdateCheck(context) {
1482
1501
  }
1483
1502
 
1484
1503
  /**
1485
- * Generate settings.json with CCASP update check hook
1504
+ * Generate settings.json with CCASP update check hook and usage tracking
1486
1505
  */
1487
1506
  function generateSettingsJson(projectName) {
1488
1507
  return JSON.stringify({
@@ -1502,6 +1521,17 @@ function generateSettingsJson(projectName) {
1502
1521
  }
1503
1522
  ]
1504
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
+ }
1505
1535
  ]
1506
1536
  }
1507
1537
  }, null, 2);
@@ -1738,6 +1768,19 @@ export async function runInit(options = {}) {
1738
1768
  console.log(chalk.blue(' ○ hooks/ccasp-update-check.js exists (preserved)'));
1739
1769
  }
1740
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
+
1741
1784
  console.log('');
1742
1785
 
1743
1786
  // Step 4: Select optional features
@@ -1849,53 +1892,226 @@ export async function runInit(options = {}) {
1849
1892
  // Step 6: Check for existing commands that would be overwritten
1850
1893
  const commandsToOverwrite = finalCommands.filter(cmd => existingCmdNames.includes(cmd));
1851
1894
 
1895
+ // Track commands that need smart merge handling
1896
+ const smartMergeDecisions = {};
1897
+
1852
1898
  let overwrite = options.force || false;
1853
1899
  if (commandsToOverwrite.length > 0 && !overwrite) {
1854
- console.log(chalk.yellow.bold(' ⚠ The following commands already exist:'));
1855
- for (const cmd of commandsToOverwrite) {
1856
- console.log(chalk.yellow(` • /${cmd}`));
1857
- }
1858
- console.log('');
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('');
1859
1918
 
1860
- const { overwriteChoice } = await inquirer.prompt([
1861
- {
1862
- type: 'list',
1863
- name: 'overwriteChoice',
1864
- message: 'How would you like to handle existing commands?',
1865
- choices: [
1866
- { name: 'Skip existing - only install new commands (recommended)', value: 'skip' },
1867
- { name: 'Overwrite with backup - save existing to .claude/backups/ first', value: 'backup' },
1868
- { name: 'Overwrite all - replace existing (no backup)', value: 'overwrite' },
1869
- { name: 'Cancel installation', value: 'cancel' },
1870
- ],
1871
- },
1872
- ]);
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
+ }
1873
1937
 
1874
- if (overwriteChoice === 'cancel') {
1875
- console.log(chalk.dim('\nCancelled. No changes made.'));
1876
- return;
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
+ }
1877
2026
  }
1878
2027
 
1879
- overwrite = overwriteChoice === 'overwrite' || overwriteChoice === 'backup';
1880
- const createBackups = overwriteChoice === 'backup';
1881
-
1882
- if (!overwrite) {
1883
- // Filter out existing commands (keep only new ones + required)
1884
- const filtered = finalCommands.filter((c) => !existingCmdNames.includes(c) || requiredCommands.includes(c));
1885
- finalCommands.length = 0;
1886
- finalCommands.push(...filtered);
1887
- console.log(chalk.green(`\n ✓ Will install ${finalCommands.length} new command(s), preserving ${commandsToOverwrite.length} existing`));
1888
- } else if (createBackups) {
1889
- console.log(chalk.cyan(`\n ✓ Will backup and overwrite ${commandsToOverwrite.length} existing command(s)`));
1890
- } else {
1891
- console.log(chalk.yellow(`\n ⚠ Will overwrite ${commandsToOverwrite.length} existing command(s)`));
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
+ }
1892
2091
  }
1893
2092
  }
1894
2093
 
1895
2094
  // Track if we should create backups (set outside the if block for use later)
2095
+ // Now also considers smart merge decisions
1896
2096
  const createBackups = options.backup || (typeof overwrite !== 'undefined' && commandsToOverwrite.length > 0 && !options.force);
1897
2097
  let backedUpFiles = [];
1898
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
+
1899
2115
  // Step 7: Install commands
1900
2116
  console.log(chalk.bold('Step 6: Installing slash commands\n'));
1901
2117
 
@@ -1916,6 +2132,11 @@ export async function runInit(options = {}) {
1916
2132
 
1917
2133
  for (const cmdName of finalCommands) {
1918
2134
  try {
2135
+ // Skip commands that were marked to skip in smart merge
2136
+ if (shouldSkipCommand(cmdName)) {
2137
+ continue;
2138
+ }
2139
+
1919
2140
  const cmdPath = join(commandsDir, `${cmdName}.md`);
1920
2141
 
1921
2142
  let content;
@@ -1938,8 +2159,8 @@ export async function runInit(options = {}) {
1938
2159
  }
1939
2160
  }
1940
2161
 
1941
- // Create backup if overwriting existing file
1942
- if (existsSync(cmdPath) && createBackups) {
2162
+ // Create backup if overwriting existing file (respects smart merge decisions)
2163
+ if (existsSync(cmdPath) && shouldBackupCommand(cmdName)) {
1943
2164
  const backupPath = createBackup(cmdPath);
1944
2165
  if (backupPath) {
1945
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('Credentials will be stored in .gtask/testing.json');
247
- console.log(chalk.dim('This file will be added to .gitignore'));
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) {
@@ -1,16 +1,66 @@
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
+ },
3
44
  {
4
45
  "version": "1.0.12",
5
46
  "date": "2026-01-30",
6
- "summary": "Release notes pending",
7
- "highlights": [],
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
+ ],
8
53
  "newFeatures": {
9
54
  "commands": [],
10
55
  "agents": [],
11
56
  "skills": [],
12
57
  "hooks": [],
13
- "other": []
58
+ "other": [
59
+ {
60
+ "name": "project-impl-banner",
61
+ "description": "Recommends running /project-impl for new installations"
62
+ }
63
+ ]
14
64
  },
15
65
  "breaking": [],
16
66
  "deprecated": []
@@ -18,8 +68,11 @@
18
68
  {
19
69
  "version": "1.0.11",
20
70
  "date": "2026-01-30",
21
- "summary": "Release notes pending",
22
- "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
+ ],
23
76
  "newFeatures": {
24
77
  "commands": [],
25
78
  "agents": [],
@@ -413,6 +466,20 @@
413
466
  "update-check": {
414
467
  "addedIn": "1.0.5",
415
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
416
483
  }
417
484
  },
418
485
  "optionalFeatures": {