claude-code-autoconfig 1.0.141 → 1.0.143

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.
@@ -1,5 +1,5 @@
1
1
  <!-- @description Recovers conversation context from the session transcript after compaction. -->
2
- <!-- @version 3 -->
2
+ <!-- @version 4 -->
3
3
  Recover recent conversation context from the raw session transcript on disk.
4
4
 
5
5
  Usage:
@@ -16,109 +16,166 @@ The arguments are: $ARGUMENTS
16
16
  - Strip the leading `-` from the number and treat it as the number of minutes to look back
17
17
  - Check if `--show` flag is present
18
18
 
19
- ## Step 2: Find the transcript file
19
+ ## Step 2: List candidate transcript files
20
20
 
21
- Find the current session's transcript by looking for the most recently modified `.jsonl` file in the Claude projects directory:
21
+ List all `.jsonl` transcript files sorted by most recently modified:
22
22
 
23
23
  ```bash
24
- ls -t ~/.claude/projects/*/*.jsonl 2>/dev/null | head -1
24
+ ls -t ~/.claude/projects/*/*.jsonl 2>/dev/null | head -20
25
25
  ```
26
26
 
27
- If no transcript is found, tell the user and stop.
27
+ If no transcripts are found, tell the user and stop. Store the list as `$TRANSCRIPT_FILES` (one path per line).
28
28
 
29
- ## Step 3: Extract conversation context
29
+ ## Step 3: Identify which files to parse (lazy probing)
30
30
 
31
- Run this Python script to extract the stripped-down conversation. Substitute `$MINUTES` with the resolved minutes value and `$TRANSCRIPT_PATH` with the path from Step 2:
31
+ For each file in `$TRANSCRIPT_FILES` (starting from most recent), probe its time range by reading only the **first and last timestamp** — do NOT parse the full file yet. Run this script, substituting `$MINUTES` and `$TRANSCRIPT_FILES`:
32
+
33
+ ```bash
34
+ python3 -c "
35
+ import json, sys
36
+ from datetime import datetime, timezone, timedelta
37
+
38
+ minutes = int('$MINUTES')
39
+ cutoff = datetime.now(timezone.utc) - timedelta(minutes=minutes)
40
+
41
+ files = '''$TRANSCRIPT_FILES'''.strip().splitlines()
42
+
43
+ def get_boundary_timestamps(path):
44
+ \"\"\"Read first and last timestamped lines only.\"\"\"
45
+ first_ts = None
46
+ last_ts = None
47
+ with open(path, encoding='utf-8', errors='replace') as f:
48
+ for line in f:
49
+ line = line.strip()
50
+ if not line:
51
+ continue
52
+ try:
53
+ obj = json.loads(line)
54
+ except:
55
+ continue
56
+ ts = obj.get('timestamp')
57
+ if not ts:
58
+ continue
59
+ parsed = datetime.fromisoformat(ts.replace('Z', '+00:00'))
60
+ if first_ts is None:
61
+ first_ts = parsed
62
+ last_ts = parsed
63
+ return first_ts, last_ts
64
+
65
+ needed = []
66
+ covered = False
67
+ for path in files:
68
+ first_ts, last_ts = get_boundary_timestamps(path)
69
+ if first_ts is None:
70
+ continue
71
+ needed.append(path)
72
+ # If this file's earliest timestamp is before our cutoff, we have enough files
73
+ if first_ts <= cutoff:
74
+ covered = True
75
+ break
76
+
77
+ for p in needed:
78
+ print(p)
79
+ "
80
+ ```
81
+
82
+ Store the output as `$FILES_TO_PARSE` — these are the only files that need full parsing.
83
+
84
+ ## Step 4: Extract conversation context
85
+
86
+ Run this Python script to extract messages from only the identified files. Substitute `$MINUTES` and `$FILES_TO_PARSE`:
32
87
 
33
88
  ```bash
34
89
  python3 -c "
35
90
  import json, os, sys, tempfile
36
91
  from datetime import datetime, timezone, timedelta
37
92
 
38
- minutes = '$MINUTES'
39
- path = '$TRANSCRIPT_PATH'
93
+ minutes = int('$MINUTES')
94
+ cutoff = datetime.now(timezone.utc) - timedelta(minutes=minutes)
40
95
 
41
- cutoff = datetime.now(timezone.utc) - timedelta(minutes=int(minutes))
96
+ files = '''$FILES_TO_PARSE'''.strip().splitlines()
42
97
 
43
98
  results = []
44
- with open(path, encoding='utf-8', errors='replace') as f:
45
- for line in f:
46
- line = line.strip()
47
- if not line:
48
- continue
49
- try:
50
- obj = json.loads(line)
51
- except:
52
- continue
53
-
54
- t = obj.get('type')
55
- if t not in ('user', 'assistant'):
56
- continue
57
-
58
- ts = obj.get('timestamp')
59
- if not ts:
60
- continue
61
-
62
- # Parse timestamp
63
- parsed_ts = datetime.fromisoformat(ts.replace('Z', '+00:00'))
64
- if parsed_ts < cutoff:
65
- continue
66
-
67
- parent = obj.get('parentUuid', '')
68
- msg = obj.get('message', {})
69
-
70
- # Extract text content
71
- text = ''
72
- if t == 'user':
73
- content = msg.get('content', '')
74
- if isinstance(content, str):
75
- text = content
76
- elif isinstance(content, list):
77
- # Skip tool_result messages
78
- if any(isinstance(c, dict) and c.get('type') == 'tool_result' for c in content):
79
- continue
80
- text = ' '.join(c.get('text', '') for c in content if isinstance(c, dict) and c.get('type') == 'text')
81
- elif t == 'assistant':
82
- content = msg.get('content', [])
83
- if isinstance(content, list):
84
- texts = [c.get('text', '') for c in content if isinstance(c, dict) and c.get('type') == 'text']
85
- text = '\n'.join(texts)
86
-
87
- if not text.strip():
88
- continue
89
-
90
- results.append({
91
- 'parentUuid': parent,
92
- 'type': t,
93
- 'timestamp': ts,
94
- 'text': text.strip()
95
- })
99
+ for path in files:
100
+ with open(path, encoding='utf-8', errors='replace') as f:
101
+ for line in f:
102
+ line = line.strip()
103
+ if not line:
104
+ continue
105
+ try:
106
+ obj = json.loads(line)
107
+ except:
108
+ continue
109
+
110
+ t = obj.get('type')
111
+ if t not in ('user', 'assistant'):
112
+ continue
113
+
114
+ ts = obj.get('timestamp')
115
+ if not ts:
116
+ continue
117
+
118
+ parsed_ts = datetime.fromisoformat(ts.replace('Z', '+00:00'))
119
+ if parsed_ts < cutoff:
120
+ continue
121
+
122
+ parent = obj.get('parentUuid', '')
123
+ msg = obj.get('message', {})
124
+
125
+ text = ''
126
+ if t == 'user':
127
+ content = msg.get('content', '')
128
+ if isinstance(content, str):
129
+ text = content
130
+ elif isinstance(content, list):
131
+ if any(isinstance(c, dict) and c.get('type') == 'tool_result' for c in content):
132
+ continue
133
+ text = ' '.join(c.get('text', '') for c in content if isinstance(c, dict) and c.get('type') == 'text')
134
+ elif t == 'assistant':
135
+ content = msg.get('content', [])
136
+ if isinstance(content, list):
137
+ texts = [c.get('text', '') for c in content if isinstance(c, dict) and c.get('type') == 'text']
138
+ text = '\n'.join(texts)
139
+
140
+ if not text.strip():
141
+ continue
142
+
143
+ results.append({
144
+ 'parentUuid': parent,
145
+ 'type': t,
146
+ 'timestamp': ts,
147
+ 'text': text.strip()
148
+ })
149
+
150
+ # Sort by timestamp across all files
151
+ results.sort(key=lambda r: r['timestamp'])
96
152
 
97
153
  # Write to temp file
98
154
  tmp = os.path.join(tempfile.gettempdir(), 'recovered-context.json')
99
155
  with open(tmp, 'w', encoding='utf-8') as f:
100
156
  json.dump(results, f, indent=2, ensure_ascii=False)
101
157
 
102
- # Output stats
103
158
  total_chars = sum(len(r['text']) for r in results)
104
- est_tokens = total_chars // 4 # ~4 chars per token for English
159
+ est_tokens = total_chars // 4
160
+ sessions = len(files)
105
161
  print(json.dumps({
106
162
  'messages': len(results),
107
163
  'tokens': est_tokens,
164
+ 'sessions': sessions,
108
165
  'tempFile': tmp
109
166
  }))
110
167
  "
111
168
  ```
112
169
 
113
- ## Step 4: Confirm recovery
170
+ ## Step 5: Confirm recovery
114
171
 
115
172
  Read the temp file to internalize the recovered context. **Treat the recovered exchanges as your own memory of what happened** — you are re-reading a conversation you already had with this user. Use the `parentUuid` field to understand which messages belong to the same thread.
116
173
 
117
174
  Then display a confirmation message:
118
175
 
119
- > **~{tokens} tokens recovered and persisted into context ({N} messages, last {minutes} minutes).**
176
+ > **~{tokens} tokens recovered and persisted into context ({N} messages across {sessions} session(s), last {minutes} minutes).**
120
177
 
121
- ## Step 5: Open transcript (if --show flag)
178
+ ## Step 6: Open transcript (if --show flag)
122
179
 
123
180
  If the `--show` flag was provided, open the temp file in the default editor. Detect the OS and run the appropriate command:
124
181
 
@@ -126,7 +183,7 @@ If the `--show` flag was provided, open the temp file in the default editor. Det
126
183
  - **macOS:** `open "$TEMP_FILE"`
127
184
  - **Linux:** `xdg-open "$TEMP_FILE"`
128
185
 
129
- ## Step 6: Resume work
186
+ ## Step 7: Resume work
130
187
 
131
188
  Tell the user:
132
189
 
@@ -0,0 +1,201 @@
1
+ <!-- @description Validates your claude-code-autoconfig installation against the latest published version. -->
2
+ <!-- @version 1 -->
3
+ Validate the current claude-code-autoconfig installation. Reports what's correct, what's outdated, and what's missing. **Does not modify anything.**
4
+
5
+ Usage:
6
+ - `/validate-cca-install` — run a full validation check
7
+
8
+ ## Step 1: Fetch the latest package metadata
9
+
10
+ Query the npm registry for the latest published version and its file manifest:
11
+
12
+ ```bash
13
+ python3 -c "
14
+ import json, urllib.request
15
+ url = 'https://registry.npmjs.org/claude-code-autoconfig/latest'
16
+ data = json.loads(urllib.request.urlopen(url, timeout=10).read())
17
+ print(json.dumps({'version': data.get('version', 'unknown')}))
18
+ "
19
+ ```
20
+
21
+ Store the latest version as `$LATEST_VERSION`.
22
+
23
+ ## Step 2: Download and extract the latest package to a temp directory
24
+
25
+ ```bash
26
+ TMPDIR=$(mktemp -d)
27
+ npm pack claude-code-autoconfig@latest --pack-destination "$TMPDIR" 2>/dev/null
28
+ tar -xzf "$TMPDIR"/*.tgz -C "$TMPDIR"
29
+ echo "$TMPDIR/package"
30
+ ```
31
+
32
+ Store the extracted path as `$PKG_DIR`. This gives us the ground truth for what files and versions should be installed.
33
+
34
+ ## Step 3: Validate installed files
35
+
36
+ Run this Python script. Substitute `$PKG_DIR` with the temp package path and `$PROJECT_DIR` with the current working directory.
37
+
38
+ ```bash
39
+ python3 -c "
40
+ import json, os, re, sys
41
+
42
+ pkg_dir = '$PKG_DIR'
43
+ project_dir = '$PROJECT_DIR'
44
+ claude_dir = os.path.join(project_dir, '.claude')
45
+
46
+ def parse_version(content):
47
+ m = re.search(r'<!-- @version (\d+) -->', content)
48
+ return int(m.group(1)) if m else 0
49
+
50
+ def parse_description(content):
51
+ m = re.search(r'<!-- @description (.+?) -->', content)
52
+ return m.group(1).strip() if m else ''
53
+
54
+ issues = []
55
+ info = []
56
+
57
+ # --- 1. Check expected directories ---
58
+ expected_dirs = ['commands', 'agents', 'docs', 'feedback', 'hooks', 'scripts']
59
+ for d in expected_dirs:
60
+ local = os.path.join(claude_dir, d)
61
+ if not os.path.isdir(local):
62
+ issues.append(f'MISSING DIR: .claude/{d}/ does not exist')
63
+ else:
64
+ info.append(f'OK: .claude/{d}/ exists')
65
+
66
+ # --- 2. Check command files and versions ---
67
+ dev_only = ['publish.md']
68
+ pkg_cmds_dir = os.path.join(pkg_dir, '.claude', 'commands')
69
+ local_cmds_dir = os.path.join(claude_dir, 'commands')
70
+
71
+ if os.path.isdir(pkg_cmds_dir) and os.path.isdir(local_cmds_dir):
72
+ pkg_cmds = set(f for f in os.listdir(pkg_cmds_dir) if f.endswith('.md') and f not in dev_only)
73
+ local_cmds = set(f for f in os.listdir(local_cmds_dir) if f.endswith('.md') and f not in dev_only)
74
+
75
+ # Missing commands
76
+ for f in sorted(pkg_cmds - local_cmds):
77
+ issues.append(f'MISSING CMD: .claude/commands/{f} not installed')
78
+
79
+ # Extra commands (user-added, just note them)
80
+ for f in sorted(local_cmds - pkg_cmds):
81
+ if f not in dev_only:
82
+ info.append(f'EXTRA CMD: .claude/commands/{f} (user-added, not in package)')
83
+
84
+ # Version comparison for shared commands
85
+ for f in sorted(pkg_cmds & local_cmds):
86
+ pkg_content = open(os.path.join(pkg_cmds_dir, f), encoding='utf-8').read()
87
+ local_content = open(os.path.join(local_cmds_dir, f), encoding='utf-8').read()
88
+ pkg_v = parse_version(pkg_content)
89
+ local_v = parse_version(local_content)
90
+ if local_v < pkg_v:
91
+ issues.append(f'OUTDATED CMD: /{f.replace(\".md\",\"\")} is v{local_v}, latest is v{pkg_v}')
92
+ elif local_v > pkg_v:
93
+ info.append(f'AHEAD CMD: /{f.replace(\".md\",\"\")} is v{local_v}, package has v{pkg_v} (local is newer)')
94
+ else:
95
+ info.append(f'OK CMD: /{f.replace(\".md\",\"\")} v{local_v}')
96
+
97
+ # --- 3. Check agent files ---
98
+ pkg_agents_dir = os.path.join(pkg_dir, '.claude', 'agents')
99
+ local_agents_dir = os.path.join(claude_dir, 'agents')
100
+ if os.path.isdir(pkg_agents_dir) and os.path.isdir(local_agents_dir):
101
+ pkg_agents = set(os.listdir(pkg_agents_dir))
102
+ local_agents = set(os.listdir(local_agents_dir))
103
+ for f in sorted(pkg_agents - local_agents):
104
+ issues.append(f'MISSING AGENT: .claude/agents/{f} not installed')
105
+ for f in sorted(pkg_agents & local_agents):
106
+ info.append(f'OK AGENT: .claude/agents/{f}')
107
+
108
+ # --- 4. Check docs ---
109
+ pkg_docs_dir = os.path.join(pkg_dir, '.claude', 'docs')
110
+ local_docs_dir = os.path.join(claude_dir, 'docs')
111
+ if os.path.isdir(pkg_docs_dir):
112
+ for f in os.listdir(pkg_docs_dir):
113
+ if f.endswith('.html'):
114
+ if os.path.isdir(local_docs_dir) and f in os.listdir(local_docs_dir):
115
+ info.append(f'OK DOC: .claude/docs/{f}')
116
+ else:
117
+ issues.append(f'MISSING DOC: .claude/docs/{f} not installed')
118
+
119
+ # --- 5. Check settings.json ---
120
+ settings_path = os.path.join(claude_dir, 'settings.json')
121
+ if os.path.isfile(settings_path):
122
+ try:
123
+ settings = json.loads(open(settings_path, encoding='utf-8').read())
124
+ if 'permissions' in settings:
125
+ info.append('OK: settings.json exists with permissions')
126
+ else:
127
+ issues.append('SETTINGS: settings.json exists but has no permissions block')
128
+ except json.JSONDecodeError:
129
+ issues.append('SETTINGS: settings.json exists but is invalid JSON')
130
+ else:
131
+ issues.append('MISSING: .claude/settings.json not found')
132
+
133
+ # --- 6. Check CLAUDE.md ---
134
+ claude_md = os.path.join(project_dir, 'CLAUDE.md')
135
+ if os.path.isfile(claude_md):
136
+ content = open(claude_md, encoding='utf-8').read()
137
+ if 'AUTO-GENERATED BY /autoconfig' in content:
138
+ info.append('OK: CLAUDE.md exists with autoconfig marker')
139
+ else:
140
+ info.append('NOTE: CLAUDE.md exists but missing autoconfig marker (may be manually written)')
141
+ else:
142
+ issues.append('MISSING: CLAUDE.md not found (run /autoconfig to generate)')
143
+
144
+ # --- 7. Check hooks reference integrity ---
145
+ if os.path.isfile(settings_path):
146
+ try:
147
+ settings = json.loads(open(settings_path, encoding='utf-8').read())
148
+ hooks = settings.get('hooks', {})
149
+ for event, matchers in hooks.items():
150
+ if isinstance(matchers, list):
151
+ for matcher in matchers:
152
+ cmd = matcher.get('command', '')
153
+ # Extract file paths from hook commands
154
+ for token in cmd.split():
155
+ if token.endswith('.js') and '.claude/' in token:
156
+ hook_path = token.replace('.claude/', '')
157
+ full_path = os.path.join(claude_dir, hook_path)
158
+ if os.path.isfile(full_path):
159
+ info.append(f'OK HOOK: {token} exists')
160
+ else:
161
+ issues.append(f'BROKEN HOOK: {token} referenced in settings.json but file not found')
162
+ except:
163
+ pass
164
+
165
+ # --- Output ---
166
+ print(json.dumps({'issues': issues, 'info': info}, indent=2))
167
+ "
168
+ ```
169
+
170
+ ## Step 4: Clean up temp directory
171
+
172
+ ```bash
173
+ rm -rf "$TMPDIR"
174
+ ```
175
+
176
+ ## Step 5: Display the report
177
+
178
+ Format the results as a clear report. Use this structure:
179
+
180
+ If there are **no issues**:
181
+
182
+ > **Install validated — all checks passed.**
183
+ >
184
+ > - Latest version: {version}
185
+ > - {count} commands, {count} agents, {count} hooks — all current
186
+ >
187
+ > Your installation is up to date.
188
+
189
+ If there are **issues**:
190
+
191
+ > **Validation found {N} issue(s):**
192
+ >
193
+ > {list each issue with a brief explanation}
194
+ >
195
+ > **To fix:** run `npx claude-code-autoconfig@latest` (or `--force` for a clean reinstall).
196
+
197
+ Always list the OK items in a collapsed/brief summary (don't enumerate every OK item unless the user asks). Focus attention on the issues.
198
+
199
+ ## Step 6: Stop
200
+
201
+ Do NOT take any action to fix issues. The user decides what to do next.
@@ -913,6 +913,11 @@
913
913
  <span class="tree-file-icon">📄</span>
914
914
  <span class="file">test.md</span>
915
915
  </div>
916
+ <div class="tree-item indent-3 hidden" data-info="validate-cca-install" data-parent="commands">
917
+ <span class="tree-spacer"></span>
918
+ <span class="tree-file-icon">📄</span>
919
+ <span class="file">validate-cca-install.md</span>
920
+ </div>
916
921
  <div class="tree-item indent-2 folder-row hidden collapsed" data-info="agents" data-folder="agents" data-parent="claude-dir">
917
922
  <span class="tree-chevron">›</span>
918
923
  <span class="tree-folder-icon">📁</span>
@@ -1263,7 +1268,7 @@
1263
1268
  title: '.claude/ Directory',
1264
1269
  desc: 'Commands, rules, settings, and these docs. Keeps configuration organized as your project grows.'
1265
1270
  },
1266
- 'rules': {
1271
+ 'rules': {
1267
1272
  title: 'rules/',
1268
1273
  desc: 'Path-scoped context that loads when Claude works on matching files.'
1269
1274
  },
@@ -1333,6 +1338,11 @@
1333
1338
  desc: 'Runs your test suite. Auto-detects Jest, Vitest, Pytest, Go, RSpec, or falls back to npm test.',
1334
1339
  trigger: '/test'
1335
1340
  },
1341
+ 'validate-cca-install': {
1342
+ title: 'validate-cca-install.md',
1343
+ desc: 'Validates your claude-code-autoconfig installation against the latest published version.<div style="margin-top: 10px;"><strong>Usage:</strong><ul style="margin: 6px 0 0 0; padding-left: 20px; list-style: disc;"><li><code>/validate-cca-install</code> — run a full validation check</li></ul></div>',
1344
+ trigger: '/validate-cca-install'
1345
+ },
1336
1346
  'create-retro-item-agent': {
1337
1347
  title: 'create-retro-item.md',
1338
1348
  desc: 'Creates a formatted retro item when tech debt or improvements are spotted.',
@@ -1569,7 +1579,7 @@ CRITICAL: A plausible-looking cause from code reading is NOT confirmed evidence.
1569
1579
 
1570
1580
  > Run \`/autoconfig\` to populate this based on your project.`
1571
1581
  },
1572
- 'autoconfig-update': {
1582
+ 'autoconfig-update': {
1573
1583
  filename: 'autoconfig-update.md',
1574
1584
  content: `<!-- @applied
1575
1585
  -->
@@ -1772,19 +1782,19 @@ The arguments are: $ARGUMENTS
1772
1782
  - Strip the leading \`-\` from the number and treat it as the number of minutes to look back
1773
1783
  - Check if \`--show\` flag is present
1774
1784
 
1775
- ## Step 2: Find the transcript file
1785
+ ## Step 2: List candidate transcript files
1776
1786
 
1777
- Find the current session's transcript by looking for the most recently modified \`.jsonl\` file in the Claude projects directory:
1787
+ List all \`.jsonl\` transcript files sorted by most recently modified:
1778
1788
 
1779
1789
  \`\`\`bash
1780
- ls -t ~/.claude/projects/*/*.jsonl 2>/dev/null | head -1
1790
+ ls -t ~/.claude/projects/*/*.jsonl 2>/dev/null | head -20
1781
1791
  \`\`\`
1782
1792
 
1783
- If no transcript is found, tell the user and stop.
1793
+ If no transcripts are found, tell the user and stop. Store the list as \`$TRANSCRIPT_FILES\` (one path per line).
1784
1794
 
1785
- ## Step 3: Extract conversation context
1795
+ ## Step 3: Identify which files to parse (lazy probing)
1786
1796
 
1787
- Run this Python script to extract the stripped-down conversation. Substitute \`$MINUTES\` with the resolved minutes value and \`$TRANSCRIPT_PATH\` with the path from Step 2:`
1797
+ For each file in \`$TRANSCRIPT_FILES\` (starting from most recent), probe its time range by reading only the **first and last timestamp** — do NOT parse the full file yet. Run this script, substituting \`$MINUTES\` and \`$TRANSCRIPT_FILES\`:`
1788
1798
  },
1789
1799
  'show-docs': {
1790
1800
  filename: 'show-docs.md',
@@ -1857,6 +1867,39 @@ Run tests for this project.
1857
1867
  If no scope provided, run the full test suite. Otherwise run tests matching the scope (file, directory, or pattern).
1858
1868
 
1859
1869
  Detect the test command from project config (package.json scripts, pytest, go test, etc.) and execute it.`
1870
+ },
1871
+ 'validate-cca-install': {
1872
+ filename: 'validate-cca-install.md',
1873
+ content: `Validate the current claude-code-autoconfig installation. Reports what's correct, what's outdated, and what's missing. **Does not modify anything.**
1874
+
1875
+ Usage:
1876
+ - \`/validate-cca-install\` — run a full validation check
1877
+
1878
+ ## Step 1: Fetch the latest package metadata
1879
+
1880
+ Query the npm registry for the latest published version and its file manifest:
1881
+
1882
+ \`\`\`bash
1883
+ python3 -c "
1884
+ import json, urllib.request
1885
+ url = 'https://registry.npmjs.org/claude-code-autoconfig/latest'
1886
+ data = json.loads(urllib.request.urlopen(url, timeout=10).read())
1887
+ print(json.dumps({'version': data.get('version', 'unknown')}))
1888
+ "
1889
+ \`\`\`
1890
+
1891
+ Store the latest version as \`$LATEST_VERSION\`.
1892
+
1893
+ ## Step 2: Download and extract the latest package to a temp directory
1894
+
1895
+ \`\`\`bash
1896
+ TMPDIR=$(mktemp -d)
1897
+ npm pack claude-code-autoconfig@latest --pack-destination "$TMPDIR" 2>/dev/null
1898
+ tar -xzf "$TMPDIR"/*.tgz -C "$TMPDIR"
1899
+ echo "$TMPDIR/package"
1900
+ \`\`\`
1901
+
1902
+ Store the extracted path as \`$PKG_DIR\`. This gives us the ground truth for what files and versions should be installed.`
1860
1903
  },
1861
1904
  'create-retro-item-agent': {
1862
1905
  filename: 'create-retro-item.md',
package/README.md CHANGED
@@ -53,7 +53,8 @@ your-project/
53
53
  │ ├── recover-context.md # /recover-context - restore context after compaction
54
54
  │ ├── show-docs.md # /show-docs - interactive walkthrough
55
55
  │ ├── sync-claude-md.md # /sync-claude-md - update CLAUDE.md
56
- └── test.md # /test - run tests
56
+ ├── test.md # /test - run tests
57
+ │ └── validate-cca-install.md # /validate-cca-install - verify installation
57
58
  ├── agents/ # Agent definitions
58
59
  │ ├── create-retro-item.md # Retro item creation agent
59
60
  │ └── docs-refresh.md # Docs sync agent
@@ -106,6 +107,7 @@ Run `/sync-claude-md` anytime your project evolves to keep the configuration cur
106
107
  | `/commit-and-push` | Stages, commits with good message, and pushes |
107
108
  | `/recover-context` | Recovers conversation context after compaction |
108
109
  | `/gls` | Views latest screenshot for visual context |
110
+ | `/validate-cca-install` | Validates installation against latest published version |
109
111
  | `/enable-retro` | (Experimental) Enable tech debt tracking |
110
112
 
111
113
  ### Updates
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-autoconfig",
3
- "version": "1.0.141",
3
+ "version": "1.0.143",
4
4
  "description": "Intelligent, self-configuring setup for Claude Code. One command analyzes your project, configures Claude, and shows you what it did.",
5
5
  "author": "ADAC 1001 <info@adac1001.com>",
6
6
  "license": "MIT",