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.
- package/.claude-plugin/plugin.json +17 -0
- package/LICENSE +21 -0
- package/README.md +298 -0
- package/agents/component-designer.md +261 -0
- package/agents/plugin-inspector.md +160 -0
- package/agents/release-executor.md +349 -0
- package/commands/infi-component-creator.md +132 -0
- package/commands/infi-ecc-helper.md +44 -0
- package/commands/infi-release.md +83 -0
- package/hooks/hooks.json +53 -0
- package/install.sh +237 -0
- package/package.json +50 -0
- package/rules/common/agents.md +28 -0
- package/rules/common/development-workflow.md +26 -0
- package/rules/common/git-workflow.md +45 -0
- package/rules/common/hooks.md +36 -0
- package/scripts/hooks/pre-compact.js +72 -0
- package/scripts/hooks/session-end.js +72 -0
- package/scripts/hooks/session-start.js +124 -0
- package/scripts/hooks/suggest-compact.js +58 -0
- package/scripts/lib/session-aliases.js +481 -0
- package/scripts/lib/session-manager.js +442 -0
- package/scripts/lib/utils.js +593 -0
- package/skills/component-templates/SKILL.md +306 -0
- package/skills/release-workflow/SKILL.md +180 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SessionEnd hook — Persist session state on end.
|
|
5
|
+
*
|
|
6
|
+
* Saves the current session state (build system, working directory, timestamp,
|
|
7
|
+
* environment details) so the next session can pick up where this one left off.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const {
|
|
13
|
+
readStdinJson, log, output,
|
|
14
|
+
getSessionsDir, ensureDir, getSessionIdShort,
|
|
15
|
+
getDateTimeString, getProjectName, readFile, writeFile,
|
|
16
|
+
} = require('../lib/utils');
|
|
17
|
+
|
|
18
|
+
function detectBuildDir() {
|
|
19
|
+
const candidates = ['build', 'cmake-build-debug', 'cmake-build-release', '_build', 'out/build'];
|
|
20
|
+
for (const c of candidates) {
|
|
21
|
+
if (fs.existsSync(c) && fs.statSync(c).isDirectory()) return c;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function detectBuildSystems() {
|
|
27
|
+
const systems = [];
|
|
28
|
+
if (fs.existsSync('CMakeLists.txt')) systems.push('CMake');
|
|
29
|
+
if (fs.existsSync('Makefile')) systems.push('Make');
|
|
30
|
+
if (fs.existsSync('build.ninja')) systems.push('Ninja');
|
|
31
|
+
if (fs.existsSync('BUILD') || fs.existsSync('WORKSPACE')) systems.push('Bazel');
|
|
32
|
+
if (fs.existsSync('meson.build')) systems.push('Meson');
|
|
33
|
+
return systems;
|
|
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, `session-${sessionId}.json`);
|
|
42
|
+
|
|
43
|
+
// Load existing state
|
|
44
|
+
let existingState = {};
|
|
45
|
+
const raw = readFile(stateFile);
|
|
46
|
+
if (raw) {
|
|
47
|
+
try { existingState = JSON.parse(raw); } catch { /* ignore */ }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const state = {
|
|
51
|
+
...existingState,
|
|
52
|
+
sessionEnded: getDateTimeString(),
|
|
53
|
+
project: getProjectName(),
|
|
54
|
+
cwd: process.cwd(),
|
|
55
|
+
buildSystems: detectBuildSystems(),
|
|
56
|
+
buildDir: detectBuildDir(),
|
|
57
|
+
env: {
|
|
58
|
+
cc: process.env.CC || null,
|
|
59
|
+
cxx: process.env.CXX || null,
|
|
60
|
+
cmakeGenerator: process.env.CMAKE_GENERATOR || null,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
writeFile(stateFile, JSON.stringify(state, null, 2));
|
|
65
|
+
|
|
66
|
+
log(`[infisense:session-end] Session state saved for project: ${state.project || 'unknown'}`);
|
|
67
|
+
log(`[infisense:session-end] State file: ${stateFile}`);
|
|
68
|
+
|
|
69
|
+
output(data);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
main().catch(() => process.exit(0));
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SessionStart hook — Load previous context and detect build system.
|
|
5
|
+
*
|
|
6
|
+
* On a new session, this hook:
|
|
7
|
+
* 1. Loads any saved session state from previous sessions.
|
|
8
|
+
* 2. Detects the build system (CMake, Make, Ninja, Bazel, Meson).
|
|
9
|
+
* 3. Detects package managers (Conan, vcpkg).
|
|
10
|
+
* 4. Logs a configuration summary to stderr.
|
|
11
|
+
* 5. Outputs a context summary so Claude has immediate project awareness.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const {
|
|
17
|
+
readStdinJson, log, output,
|
|
18
|
+
getSessionsDir, getSessionIdShort,
|
|
19
|
+
getDateTimeString, getProjectName,
|
|
20
|
+
commandExists, runCommand, readFile, writeFile, ensureDir,
|
|
21
|
+
} = require('../lib/utils');
|
|
22
|
+
|
|
23
|
+
function detectBuildSystem() {
|
|
24
|
+
const systems = [];
|
|
25
|
+
if (fs.existsSync('CMakeLists.txt')) systems.push('CMake');
|
|
26
|
+
if (fs.existsSync('Makefile')) systems.push('Make');
|
|
27
|
+
if (fs.existsSync('build.ninja')) systems.push('Ninja');
|
|
28
|
+
if (fs.existsSync('BUILD') || fs.existsSync('WORKSPACE')) systems.push('Bazel');
|
|
29
|
+
if (fs.existsSync('meson.build')) systems.push('Meson');
|
|
30
|
+
if (fs.existsSync('premake5.lua')) systems.push('Premake');
|
|
31
|
+
return systems;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function detectPackageManagers() {
|
|
35
|
+
const managers = [];
|
|
36
|
+
if (fs.existsSync('conanfile.txt') || fs.existsSync('conanfile.py')) managers.push('Conan');
|
|
37
|
+
if (fs.existsSync('vcpkg.json')) managers.push('vcpkg');
|
|
38
|
+
if (fs.existsSync('hunter-gate.cmake')) managers.push('Hunter');
|
|
39
|
+
if (fs.existsSync('CPM.cmake')) managers.push('CPM');
|
|
40
|
+
return managers;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function detectToolchain() {
|
|
44
|
+
const tools = {};
|
|
45
|
+
if (commandExists('gcc')) tools.gcc = true;
|
|
46
|
+
if (commandExists('g++')) tools.gpp = true;
|
|
47
|
+
if (commandExists('clang')) tools.clang = true;
|
|
48
|
+
if (commandExists('clang++')) tools.clangpp = true;
|
|
49
|
+
if (commandExists('clang-tidy')) tools.clangTidy = true;
|
|
50
|
+
if (commandExists('clang-format')) tools.clangFormat = true;
|
|
51
|
+
if (commandExists('valgrind')) tools.valgrind = true;
|
|
52
|
+
if (commandExists('cppcheck')) tools.cppcheck = true;
|
|
53
|
+
if (commandExists('cmake')) tools.cmake = true;
|
|
54
|
+
if (commandExists('ninja')) tools.ninja = true;
|
|
55
|
+
return tools;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function findBuildDir() {
|
|
59
|
+
const candidates = ['build', 'cmake-build-debug', 'cmake-build-release', '_build', 'out/build'];
|
|
60
|
+
for (const c of candidates) {
|
|
61
|
+
if (fs.existsSync(c) && fs.statSync(c).isDirectory()) return c;
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function main() {
|
|
67
|
+
const data = await readStdinJson();
|
|
68
|
+
|
|
69
|
+
// Load previous session state
|
|
70
|
+
const sessionsDir = ensureDir(getSessionsDir());
|
|
71
|
+
const sessionId = getSessionIdShort('default');
|
|
72
|
+
const stateFile = path.join(sessionsDir, `session-${sessionId}.json`);
|
|
73
|
+
let prevState = {};
|
|
74
|
+
const raw = readFile(stateFile);
|
|
75
|
+
if (raw) {
|
|
76
|
+
try { prevState = JSON.parse(raw); } catch { /* ignore */ }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Detect current environment
|
|
80
|
+
const buildSystems = detectBuildSystem();
|
|
81
|
+
const packageManagers = detectPackageManagers();
|
|
82
|
+
const toolchain = detectToolchain();
|
|
83
|
+
const buildDir = findBuildDir();
|
|
84
|
+
const project = getProjectName();
|
|
85
|
+
|
|
86
|
+
// Save new session state
|
|
87
|
+
const state = {
|
|
88
|
+
...prevState,
|
|
89
|
+
sessionStarted: getDateTimeString(),
|
|
90
|
+
project,
|
|
91
|
+
cwd: process.cwd(),
|
|
92
|
+
buildSystems,
|
|
93
|
+
packageManagers,
|
|
94
|
+
buildDir,
|
|
95
|
+
toolchain: Object.keys(toolchain),
|
|
96
|
+
resumeCount: (prevState.resumeCount || 0) + 1,
|
|
97
|
+
};
|
|
98
|
+
writeFile(stateFile, JSON.stringify(state, null, 2));
|
|
99
|
+
|
|
100
|
+
// Log summary
|
|
101
|
+
log('[infisense:session-start] ---- C/C++ Project Detected ----');
|
|
102
|
+
log(`[infisense:session-start] Project: ${project || 'unknown'}`);
|
|
103
|
+
log(`[infisense:session-start] Build system(s): ${buildSystems.join(', ') || 'none detected'}`);
|
|
104
|
+
log(`[infisense:session-start] Package manager(s): ${packageManagers.join(', ') || 'none detected'}`);
|
|
105
|
+
log(`[infisense:session-start] Build directory: ${buildDir || 'not found'}`);
|
|
106
|
+
log(`[infisense:session-start] Available tools: ${Object.keys(toolchain).join(', ') || 'none'}`);
|
|
107
|
+
if (prevState.sessionStarted) {
|
|
108
|
+
log(`[infisense:session-start] Previous session: ${prevState.sessionStarted} (resume #${state.resumeCount})`);
|
|
109
|
+
}
|
|
110
|
+
log('[infisense:session-start] ---- End Detection ----');
|
|
111
|
+
|
|
112
|
+
// Output context summary for Claude
|
|
113
|
+
const summary = {
|
|
114
|
+
project,
|
|
115
|
+
buildSystems,
|
|
116
|
+
packageManagers,
|
|
117
|
+
buildDir,
|
|
118
|
+
toolchain: Object.keys(toolchain),
|
|
119
|
+
previousSession: prevState.sessionStarted || null,
|
|
120
|
+
};
|
|
121
|
+
output(summary);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
main().catch(() => process.exit(0));
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PreToolUse hook (Edit|Write) — Suggest manual compaction at logical intervals.
|
|
5
|
+
*
|
|
6
|
+
* Tracks the number of Edit/Write operations in a temp file. Every 20 edits,
|
|
7
|
+
* it logs a suggestion to stderr reminding the developer to compact context
|
|
8
|
+
* with /compact. This helps prevent context window exhaustion during long
|
|
9
|
+
* editing sessions.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const { readStdinJson, log, output, getTempDir, ensureDir, getSessionIdShort } = require('../lib/utils');
|
|
15
|
+
|
|
16
|
+
const COMPACT_INTERVAL = 20;
|
|
17
|
+
|
|
18
|
+
function getCounterFile() {
|
|
19
|
+
const dir = path.join(getTempDir(), 'ecc-infisense');
|
|
20
|
+
ensureDir(dir);
|
|
21
|
+
const sessionId = getSessionIdShort('default');
|
|
22
|
+
return path.join(dir, `edit-counter-${sessionId}.json`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function loadCounter() {
|
|
26
|
+
const file = getCounterFile();
|
|
27
|
+
try {
|
|
28
|
+
const raw = fs.readFileSync(file, 'utf-8');
|
|
29
|
+
const data = JSON.parse(raw);
|
|
30
|
+
return typeof data.count === 'number' ? data.count : 0;
|
|
31
|
+
} catch {
|
|
32
|
+
return 0;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function saveCounter(count) {
|
|
37
|
+
const file = getCounterFile();
|
|
38
|
+
fs.writeFileSync(file, JSON.stringify({ count, updatedAt: new Date().toISOString() }), 'utf-8');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function main() {
|
|
42
|
+
const data = await readStdinJson();
|
|
43
|
+
|
|
44
|
+
const count = loadCounter() + 1;
|
|
45
|
+
saveCounter(count);
|
|
46
|
+
|
|
47
|
+
if (count > 0 && count % COMPACT_INTERVAL === 0) {
|
|
48
|
+
log('[infisense:suggest-compact] ---- Compaction Suggestion ----');
|
|
49
|
+
log(`[infisense:suggest-compact] You have made ${count} edits in this session.`);
|
|
50
|
+
log('[infisense:suggest-compact] Consider running /compact to reduce context size');
|
|
51
|
+
log('[infisense:suggest-compact] and preserve working memory for the rest of the session.');
|
|
52
|
+
log('[infisense:suggest-compact] ---- End Suggestion ----');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
output(data);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
main().catch(() => process.exit(0));
|