ecc_infisense 0.0.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.
@@ -0,0 +1,83 @@
1
+ ---
2
+ description: Git commit and npm publish with version management.
3
+ category: plugin
4
+ ---
5
+
6
+ # Release Management
7
+
8
+ Manage ECC InfiSense releases through three workflows: git update, npm publish,
9
+ and status. Delegates execution to the `release-executor` agent.
10
+
11
+ ## Usage
12
+
13
+ `/infi-release [git-update|publish|status] [options]`
14
+
15
+ If mode is omitted, present an interactive menu using AskUserQuestion:
16
+
17
+ ```
18
+ Which release workflow do you want to run?
19
+
20
+ 1. git update
21
+ Detect changes, commit with conventional commits, update CHANGELOG.md
22
+ 2. npm publish
23
+ Bump version, update CHANGELOG.md, tag, push, npm publish
24
+ 3. status
25
+ Show current version, last tag, and unreleased changes
26
+ ```
27
+
28
+ ---
29
+
30
+ ## 1. git update
31
+
32
+ Detect uncommitted changes, make all necessary file modifications, then commit.
33
+
34
+ Delegate to `release-executor` agent which will:
35
+
36
+ 1. **Detect changes** — scan git status for modified, added, deleted files
37
+ 2. **Analyze and group** — map file paths to commit types/scopes using
38
+ `release-workflow` skill conventions
39
+ 3. **Safety checks** — scan for dangerous files, debug code, validate message format
40
+ 4. **Update CHANGELOG.md** — categorize changes per Keep a Changelog format
41
+ 5. **Update documentation** — sync component counts in README.md, GUIDE.md, CLAUDE.md
42
+ 6. **Commit** — stage and commit (single or multiple atomic commits)
43
+
44
+ Show all findings and grouping plan to user. Wait for confirmation before committing.
45
+
46
+ ---
47
+
48
+ ## 2. npm publish
49
+
50
+ Full release: bump version, finalize changelog, tag, push, publish.
51
+
52
+ Delegate to `release-executor` agent which will:
53
+
54
+ 1. **Ensure clean tree** — run git update first if uncommitted changes exist
55
+ 2. **Pre-flight** — run `npm test`, abort if tests fail
56
+ 3. **Bump version** — ask user for level (patch/minor/major), update package.json
57
+ and plugin.json
58
+ 4. **Finalize changelog** — move `[Unreleased]` to versioned section
59
+ 5. **Update documentation** — sync version and counts in README.md, GUIDE.md
60
+ 6. **Commit, tag, push, publish** — single release commit with version tag
61
+
62
+ ---
63
+
64
+ ## 3. status
65
+
66
+ Read-only — show current state without making changes.
67
+
68
+ Delegate to `release-executor` agent to display:
69
+
70
+ - Current version from package.json
71
+ - Last git tag
72
+ - Commit count since last tag
73
+ - Uncommitted changes summary
74
+ - Unreleased changelog entries
75
+
76
+ ---
77
+
78
+ ## Cross-References
79
+
80
+ - Agent: `release-executor` — executes all three release workflows
81
+ - Skill: `release-workflow` — commit conventions, path-scope mapping, changelog format
82
+ - Related: `/infi-component-creator` — create components before releasing
83
+ - Related: `/infi-ecc-helper` — view current plugin overview
@@ -0,0 +1,53 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/claude-code-settings.json",
3
+ "hooks": {
4
+ "PreToolUse": [
5
+ {
6
+ "matcher": "Edit|Write",
7
+ "hooks": [
8
+ {
9
+ "type": "command",
10
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/suggest-compact.js\""
11
+ }
12
+ ],
13
+ "description": "Suggest manual compaction at logical intervals"
14
+ }
15
+ ],
16
+ "PreCompact": [
17
+ {
18
+ "matcher": "*",
19
+ "hooks": [
20
+ {
21
+ "type": "command",
22
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/pre-compact.js\""
23
+ }
24
+ ],
25
+ "description": "Save state before context compaction"
26
+ }
27
+ ],
28
+ "SessionStart": [
29
+ {
30
+ "matcher": "*",
31
+ "hooks": [
32
+ {
33
+ "type": "command",
34
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/session-start.js\""
35
+ }
36
+ ],
37
+ "description": "Load previous context and detect build system on new session"
38
+ }
39
+ ],
40
+ "SessionEnd": [
41
+ {
42
+ "matcher": "*",
43
+ "hooks": [
44
+ {
45
+ "type": "command",
46
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/session-end.js\""
47
+ }
48
+ ],
49
+ "description": "Persist session state on end"
50
+ }
51
+ ]
52
+ }
53
+ }
package/install.sh ADDED
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env bash
2
+ # install.sh — Install ECC InfiSense plugin for Claude Code.
3
+ #
4
+ # Usage:
5
+ # ./install.sh
6
+ #
7
+ # This script copies all plugin components into ~/.claude/:
8
+ # - rules/ → ~/.claude/rules/common/
9
+ # - commands/ → ~/.claude/commands/
10
+ # - agents/ → ~/.claude/agents/
11
+ # - skills/ → ~/.claude/skills/
12
+ # - hooks → ~/.claude/settings.json (merged)
13
+ #
14
+ # Update safety:
15
+ # A manifest file (~/.claude/.ecc-infisense-manifest) tracks every file
16
+ # installed by this plugin. On re-install, files listed in the old manifest
17
+ # but absent from the new version are automatically removed, without
18
+ # touching files owned by the user or other plugins.
19
+
20
+ set -euo pipefail
21
+
22
+ # Resolve symlinks — needed when invoked as `ecc-infisense-install` via npm/bun bin symlink
23
+ SCRIPT_PATH="$0"
24
+ while [ -L "$SCRIPT_PATH" ]; do
25
+ link_dir="$(cd "$(dirname "$SCRIPT_PATH")" && pwd)"
26
+ SCRIPT_PATH="$(readlink "$SCRIPT_PATH")"
27
+ # Resolve relative symlinks
28
+ [[ "$SCRIPT_PATH" != /* ]] && SCRIPT_PATH="$link_dir/$SCRIPT_PATH"
29
+ done
30
+ SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_PATH")" && pwd)"
31
+ RULES_DIR="$SCRIPT_DIR/rules"
32
+
33
+ # --- Manifest helpers ---
34
+ # The manifest tracks every file installed by this plugin so that upgrades
35
+ # can remove files that no longer exist in the new version, without touching
36
+ # files owned by the user or other plugins.
37
+
38
+ MANIFEST_FILE="$HOME/.claude/.ecc-infisense-manifest"
39
+ NEW_MANIFEST=()
40
+
41
+ # Record a file path into the new manifest (call after each cp)
42
+ record() {
43
+ NEW_MANIFEST+=("$1")
44
+ }
45
+
46
+ # Record all files under a directory tree
47
+ record_tree() {
48
+ local dir="$1"
49
+ while IFS= read -r -d '' f; do
50
+ record "$f"
51
+ done < <(find "$dir" -type f -print0 2>/dev/null)
52
+ }
53
+
54
+ # Remove files from old manifest that are not in the new manifest
55
+ cleanup_old_manifest() {
56
+ if [[ ! -f "$MANIFEST_FILE" ]]; then
57
+ return
58
+ fi
59
+
60
+ local removed=0
61
+ while IFS= read -r old_file; do
62
+ [[ -z "$old_file" ]] && continue
63
+ # Check if this file is still in the new manifest
64
+ local found=false
65
+ for new_file in "${NEW_MANIFEST[@]}"; do
66
+ if [[ "$new_file" == "$old_file" ]]; then
67
+ found=true
68
+ break
69
+ fi
70
+ done
71
+ if ! $found && [[ -f "$old_file" ]]; then
72
+ rm -f "$old_file"
73
+ removed=$((removed + 1))
74
+ fi
75
+ done < "$MANIFEST_FILE"
76
+
77
+ if [[ $removed -gt 0 ]]; then
78
+ echo "Cleaned up $removed file(s) from previous installation."
79
+ fi
80
+
81
+ # Remove empty directories left behind (only under ~/.claude/)
82
+ find "$HOME/.claude/rules" "$HOME/.claude/commands" "$HOME/.claude/agents" "$HOME/.claude/skills" \
83
+ -type d -empty -delete 2>/dev/null || true
84
+ }
85
+
86
+ # Write the new manifest to disk
87
+ save_manifest() {
88
+ mkdir -p "$(dirname "$MANIFEST_FILE")"
89
+ printf '%s\n' "${NEW_MANIFEST[@]}" > "$MANIFEST_FILE"
90
+ }
91
+
92
+ # --- Install ---
93
+
94
+ install_plugin() {
95
+ local DEST_DIR="${CLAUDE_RULES_DIR:-$HOME/.claude/rules}"
96
+ local CMD_DIR="$HOME/.claude/commands"
97
+ local AGENTS_DIR="$HOME/.claude/agents"
98
+ local SKILLS_DIR="$HOME/.claude/skills"
99
+ local COMMANDS_SRC="$SCRIPT_DIR/commands"
100
+ local AGENTS_SRC="$SCRIPT_DIR/agents"
101
+ local SKILLS_SRC="$SCRIPT_DIR/skills"
102
+ local SETTINGS_FILE="$HOME/.claude/settings.json"
103
+ local HOOKS_SRC="$SCRIPT_DIR/hooks/hooks.json"
104
+
105
+ # --- Rules ---
106
+
107
+ # Install common rules
108
+ if [[ -d "$RULES_DIR/common" ]]; then
109
+ echo "Installing rules -> $DEST_DIR/common/"
110
+ rm -rf "$DEST_DIR/common"
111
+ mkdir -p "$DEST_DIR/common"
112
+ cp -r "$RULES_DIR/common/." "$DEST_DIR/common/"
113
+ record_tree "$DEST_DIR/common"
114
+ fi
115
+
116
+ # Install language-specific rules if they exist
117
+ for lang_dir in "$RULES_DIR"/*/; do
118
+ [[ -d "$lang_dir" ]] || continue
119
+ local lang
120
+ lang="$(basename "$lang_dir")"
121
+ [[ "$lang" == "common" ]] && continue
122
+
123
+ echo "Installing $lang rules -> $DEST_DIR/$lang/"
124
+ rm -rf "$DEST_DIR/$lang"
125
+ mkdir -p "$DEST_DIR/$lang"
126
+ cp -r "$lang_dir." "$DEST_DIR/$lang/"
127
+ record_tree "$DEST_DIR/$lang"
128
+ done
129
+
130
+ echo "Rules installed to $DEST_DIR/"
131
+
132
+ # --- Commands ---
133
+ if [[ -d "$COMMANDS_SRC" ]]; then
134
+ echo "Installing commands -> $CMD_DIR/"
135
+ mkdir -p "$CMD_DIR"
136
+ for f in "$COMMANDS_SRC"/*.md; do
137
+ [[ -f "$f" ]] || continue
138
+ local dest="$CMD_DIR/$(basename "$f")"
139
+ cp "$f" "$dest"
140
+ record "$dest"
141
+ done
142
+ echo "Commands installed ($(ls "$COMMANDS_SRC"/*.md 2>/dev/null | wc -l) files)"
143
+ fi
144
+
145
+ # --- Agents ---
146
+ if [[ -d "$AGENTS_SRC" ]]; then
147
+ echo "Installing agents -> $AGENTS_DIR/"
148
+ mkdir -p "$AGENTS_DIR"
149
+ for f in "$AGENTS_SRC"/*; do
150
+ [[ -f "$f" ]] || continue
151
+ local dest="$AGENTS_DIR/$(basename "$f")"
152
+ cp "$f" "$dest"
153
+ record "$dest"
154
+ done
155
+ echo "Agents installed ($(ls "$AGENTS_SRC"/ 2>/dev/null | wc -l) files)"
156
+ fi
157
+
158
+ # --- Skills ---
159
+ if [[ -d "$SKILLS_SRC" ]]; then
160
+ echo "Installing skills -> $SKILLS_DIR/"
161
+ mkdir -p "$SKILLS_DIR"
162
+ for skill_dir in "$SKILLS_SRC"/*/; do
163
+ [[ -d "$skill_dir" ]] || continue
164
+ local skill_name
165
+ skill_name="$(basename "$skill_dir")"
166
+ local dest_skill="$SKILLS_DIR/$skill_name"
167
+ rm -rf "$dest_skill"
168
+ mkdir -p "$dest_skill"
169
+ cp -r "$skill_dir." "$dest_skill/"
170
+ record_tree "$dest_skill"
171
+ done
172
+ echo "Skills installed ($(find "$SKILLS_SRC" -maxdepth 1 -mindepth 1 -type d | wc -l) skills)"
173
+ fi
174
+
175
+ # --- Cleanup old files and save new manifest ---
176
+ cleanup_old_manifest
177
+ save_manifest
178
+
179
+ # --- Merge hooks into ~/.claude/settings.json ---
180
+ if [[ -f "$HOOKS_SRC" ]] && command -v node >/dev/null 2>&1; then
181
+ echo "Installing hooks into $SETTINGS_FILE ..."
182
+ node -e "
183
+ const fs = require('fs');
184
+ const hooksPath = '$HOOKS_SRC';
185
+ const settingsPath = '$SETTINGS_FILE';
186
+ const pluginRoot = '$SCRIPT_DIR';
187
+
188
+ // Read new hooks
189
+ const newHooks = JSON.parse(fs.readFileSync(hooksPath, 'utf8'));
190
+
191
+ // Read existing settings or create empty
192
+ let settings = {};
193
+ try {
194
+ settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
195
+ } catch {}
196
+
197
+ // Replace \${CLAUDE_PLUGIN_ROOT} with actual path in hook commands
198
+ const hooksStr = JSON.stringify(newHooks.hooks || newHooks)
199
+ .replace(/\\$\\{CLAUDE_PLUGIN_ROOT\\}/g, pluginRoot);
200
+ const resolvedHooks = JSON.parse(hooksStr);
201
+
202
+ // Merge hooks (overwrite event types from plugin)
203
+ if (!settings.hooks) settings.hooks = {};
204
+ for (const [event, matchers] of Object.entries(resolvedHooks)) {
205
+ settings.hooks[event] = matchers;
206
+ }
207
+
208
+ // Remove event types that are no longer in the plugin
209
+ const pluginEvents = Object.keys(resolvedHooks);
210
+ for (const event of Object.keys(settings.hooks)) {
211
+ if (!pluginEvents.includes(event)) {
212
+ // Check if all matchers in this event reference our plugin
213
+ const matchers = settings.hooks[event];
214
+ const allOurs = matchers.every(m =>
215
+ m.hooks && m.hooks.every(h =>
216
+ h.command && h.command.includes(pluginRoot)
217
+ )
218
+ );
219
+ if (allOurs) {
220
+ delete settings.hooks[event];
221
+ }
222
+ }
223
+ }
224
+
225
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
226
+ console.log('Hooks merged into ' + settingsPath);
227
+ "
228
+ else
229
+ echo "Warning: node not found or hooks.json missing. Hooks not installed." >&2
230
+ echo " Install Node.js 18+ and re-run to enable hooks." >&2
231
+ fi
232
+ }
233
+
234
+ install_plugin
235
+
236
+ echo ""
237
+ echo "Done. Run '/infi-ecc-helper' in Claude Code to verify."
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "ecc_infisense",
3
+ "version": "0.0.1",
4
+ "description": "Claude Code plugin for C/C++ development — agents, skills, hooks, commands, and rules for component management, release workflow, and C++ coding conventions",
5
+ "keywords": [
6
+ "claude-code",
7
+ "cpp",
8
+ "c++",
9
+ "plugin",
10
+ "agents",
11
+ "skills",
12
+ "hooks",
13
+ "rules"
14
+ ],
15
+ "author": "ECC InfiSense Contributors",
16
+ "license": "MIT",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+ssh://git@172.16.40.222:sunchaoyue/ecc-infisense.git"
20
+ },
21
+ "homepage": "http://172.16.40.222/sunchaoyue/ecc-infisense",
22
+ "bugs": {
23
+ "url": "http://172.16.40.222/sunchaoyue/ecc-infisense/issues"
24
+ },
25
+ "files": [
26
+ "agents/",
27
+ "commands/",
28
+ "hooks/",
29
+ "rules/",
30
+ "scripts/hooks/",
31
+ "scripts/lib/",
32
+ "skills/",
33
+ ".claude-plugin/plugin.json",
34
+ "install.sh"
35
+ ],
36
+ "bin": {
37
+ "ecc_infisense-install": "install.sh"
38
+ },
39
+ "scripts": {
40
+ "postinstall": "echo '\\n ecc_infisense installed!\\n Run: ./install.sh\\n Docs: http://172.16.40.222/sunchaoyue/ecc-infisense\\n'",
41
+ "lint": "markdownlint '**/*.md' --ignore node_modules",
42
+ "test": "node scripts/ci/validate-agents.js && node scripts/ci/validate-commands.js && node scripts/ci/validate-rules.js && node scripts/ci/validate-skills.js && node scripts/ci/validate-hooks.js && node scripts/ci/validate-version-sync.js && node scripts/ci/validate-cross-references.js && node tests/run-all.js"
43
+ },
44
+ "devDependencies": {
45
+ "markdownlint-cli": "^0.47.0"
46
+ },
47
+ "engines": {
48
+ "node": ">=18"
49
+ }
50
+ }
@@ -0,0 +1,28 @@
1
+ # Agent Usage Guide
2
+
3
+ ## When to Delegate
4
+
5
+ Use agents for: multi-file operations, component design, plugin analysis, release management.
6
+ Do NOT delegate: single-file edits, simple tasks where you have full context.
7
+
8
+ ## Agent Selection
9
+
10
+ | Agent | Use For |
11
+ |-------|---------|
12
+ | `@component-designer` | Design new components, analyze existing ones, rename for clarity |
13
+ | `@plugin-inspector` | Scan directories, generate categorized component index |
14
+ | `@release-executor` | Git commit workflows, npm publish, version status |
15
+
16
+ ## Coordination Patterns
17
+
18
+ - Sequential: design components → create → release
19
+ - `/infi-component-creator` delegates to `component-designer`
20
+ - `/infi-ecc-helper` delegates to `plugin-inspector`
21
+ - `/infi-release` delegates to `release-executor`
22
+
23
+ ## Best Practices
24
+
25
+ 1. Always include file paths, error messages, or design constraints
26
+ 2. Be specific: "Analyze agents/ for orphan components" not "analyze project"
27
+ 3. Share results between agents in multi-agent workflows
28
+ 4. Agent output is a starting point; refine with follow-ups
@@ -0,0 +1,26 @@
1
+ # Development Workflow
2
+
3
+ ## Core Cycle
4
+
5
+ ```
6
+ Edit → Compile-Check → Test → Commit (iterate)
7
+ ```
8
+
9
+ ## Steps
10
+
11
+ 1. Plan before implementing any non-trivial change
12
+ 2. After every code edit, verify it compiles
13
+ 3. Review your own code before committing
14
+ 4. Use `/infi-release git-update` to commit with conventional commits
15
+
16
+ ## Always Compile-Check After Edits
17
+
18
+ - After every code edit, verify it compiles
19
+ - Do not accumulate multiple edits without checking
20
+ - Quick check: `g++ -std=c++20 -fsyntax-only -Wall -Wextra file.cpp`
21
+
22
+ ## Workflow Rules
23
+
24
+ - Never commit without tests
25
+ - Never push without verification
26
+ - Keep commits atomic (one logical change)
@@ -0,0 +1,45 @@
1
+ # Git Workflow Conventions
2
+
3
+ ## Conventional Commits
4
+
5
+ Format: `<type>(<scope>): <subject>`
6
+
7
+ | Type | Use |
8
+ |------|-----|
9
+ | `feat` | New feature |
10
+ | `fix` | Bug fix |
11
+ | `docs` | Documentation |
12
+ | `refactor` | No behavior change |
13
+ | `test` | Tests |
14
+ | `chore` | Build, CI, tooling |
15
+ | `perf` | Performance |
16
+
17
+ Subject rules: lowercase, no period, imperative mood, max 72 chars.
18
+ Body explains **why**, not what. Breaking changes: `!` after type + `BREAKING CHANGE:` footer.
19
+
20
+ ## Atomic Commits
21
+
22
+ One logical change per commit. If you can say "X and Y", make two commits.
23
+
24
+ ## Branch Naming
25
+
26
+ ```
27
+ feature/<issue-id>-<short-description>
28
+ bugfix/<issue-id>-<short-description>
29
+ hotfix/<issue-id>-<short-description>
30
+ release/<version>
31
+ ```
32
+
33
+ ## Pre-Push Checklist
34
+
35
+ - [ ] Compiles without warnings (`-Wall -Wextra -Werror`)
36
+ - [ ] All tests pass
37
+ - [ ] New code has test coverage
38
+ - [ ] clang-format applied
39
+ - [ ] No debug prints or commented-out code
40
+
41
+ ## Protected Branches
42
+
43
+ - `main`: never force push, all changes via PR, requires CI + review
44
+ - `develop`: never force push, feature branches merge here
45
+ - Feature branches: force push OK, rebase on develop, delete after merge
@@ -0,0 +1,36 @@
1
+ # Hook Development Guidelines
2
+
3
+ ## Protocol
4
+
5
+ - Input: JSON from stdin (event, files, context)
6
+ - Output: JSON to stdout with `status`: `"pass"`, `"warn"`, or `"block"`
7
+ - Human messages via stderr (`log()` function)
8
+ - Exit codes: 0 = pass, 1 = hook error, 2 = intentional block
9
+
10
+ ## Performance
11
+
12
+ | Hook Type | Max Duration |
13
+ |-----------|-------------|
14
+ | Synchronous (post-edit) | 5 seconds |
15
+ | Asynchronous (post-build) | 30 seconds |
16
+ | Pre-commit | 10 seconds |
17
+
18
+ Only check changed files, not the entire project. Cache results between invocations.
19
+
20
+ ## Error Handling
21
+
22
+ A hook's internal failure must never block the developer. On crash: exit 0, log error.
23
+ Only exit 2 for intentional policy violations.
24
+
25
+ ## Testing
26
+
27
+ Test hooks with mock JSON input before deploying:
28
+ ```bash
29
+ cat mock-input.json | python3 hooks/my-hook.py
30
+ ```
31
+
32
+ ## File Patterns
33
+
34
+ Source: `*.cpp`, `*.c`, `*.cxx`, `*.cc`
35
+ Headers: `*.h`, `*.hpp`, `*.hxx`
36
+ Templates: `*.inl`, `*.tpp`
@@ -0,0 +1,72 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * PreCompact hook — Save state before context compaction.
5
+ *
6
+ * When Claude Code compacts the context window, important state can be lost.
7
+ * This hook persists the current session state (build config, recent test
8
+ * results, and pending tasks) so it can be restored after compaction.
9
+ */
10
+
11
+ const path = require('path');
12
+ const {
13
+ readStdinJson, log, output,
14
+ getSessionsDir, ensureDir, getSessionIdShort,
15
+ getDateTimeString, getProjectName, runCommand, readFile, writeFile,
16
+ } = require('../lib/utils');
17
+
18
+ function detectBuildConfig() {
19
+ const config = {};
20
+ const cmake = runCommand('cmake --version');
21
+ if (cmake.success) {
22
+ const match = cmake.output.match(/cmake version ([\d.]+)/);
23
+ config.cmakeVersion = match ? match[1] : 'unknown';
24
+ }
25
+ const buildDirs = ['build', 'cmake-build-debug', 'cmake-build-release', '_build'];
26
+ const fs = require('fs');
27
+ for (const d of buildDirs) {
28
+ if (fs.existsSync(d) && fs.statSync(d).isDirectory()) {
29
+ config.buildDir = d;
30
+ break;
31
+ }
32
+ }
33
+ return config;
34
+ }
35
+
36
+ async function main() {
37
+ const data = await readStdinJson();
38
+
39
+ const sessionsDir = ensureDir(getSessionsDir());
40
+ const sessionId = getSessionIdShort('default');
41
+ const stateFile = path.join(sessionsDir, `pre-compact-${sessionId}.json`);
42
+
43
+ const existingState = (() => {
44
+ const raw = readFile(stateFile);
45
+ if (!raw) return {};
46
+ try { return JSON.parse(raw); } catch { return {}; }
47
+ })();
48
+
49
+ const state = {
50
+ ...existingState,
51
+ timestamp: getDateTimeString(),
52
+ project: getProjectName(),
53
+ cwd: process.cwd(),
54
+ buildConfig: detectBuildConfig(),
55
+ compactionCount: (existingState.compactionCount || 0) + 1,
56
+ env: {
57
+ cc: process.env.CC || null,
58
+ cxx: process.env.CXX || null,
59
+ cmakeGenerator: process.env.CMAKE_GENERATOR || null,
60
+ },
61
+ };
62
+
63
+ writeFile(stateFile, JSON.stringify(state, null, 2));
64
+
65
+ log(`[infisense:pre-compact] Session state saved (compaction #${state.compactionCount}).`);
66
+ log(`[infisense:pre-compact] Build dir: ${state.buildConfig.buildDir || 'not detected'}`);
67
+ log(`[infisense:pre-compact] Project: ${state.project || 'unknown'}`);
68
+
69
+ output(data);
70
+ }
71
+
72
+ main().catch(() => process.exit(0));