marmot-logger 1.0.0
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 +172 -0
- package/bin/marmot.js +71 -0
- package/package.json +34 -0
- package/src/cli/disable.js +40 -0
- package/src/cli/enable.js +40 -0
- package/src/cli/init.js +85 -0
- package/src/cli/log.js +102 -0
- package/src/cli/login.js +120 -0
- package/src/cli/logs.js +93 -0
- package/src/cli/monitor.js +32 -0
- package/src/cli/status.js +72 -0
- package/src/cli/verify.js +81 -0
- package/src/core/config.js +190 -0
- package/src/core/gitignore.js +109 -0
- package/src/core/logger.js +120 -0
- package/src/core/signer.js +136 -0
- package/src/index.js +20 -0
- package/src/plugins/claude-hooks.js +134 -0
- package/src/plugins/file-monitor.js +233 -0
- package/src/plugins/git-hooks.js +177 -0
- package/src/plugins/index.js +7 -0
- package/src/plugins/makefile.js +68 -0
- package/src/plugins/terminal.js +136 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
|
|
5
|
+
const MARMOT_MARKER = '# marmot';
|
|
6
|
+
|
|
7
|
+
const MAKEFILE_SNIPPET = `# Marmot: Log make commands ${MARMOT_MARKER}
|
|
8
|
+
MARMOT_LOG_DIR := logs ${MARMOT_MARKER}
|
|
9
|
+
MARMOT_LOG_FILE := $(MARMOT_LOG_DIR)/file_events_$(shell date +%Y-%m-%d).log ${MARMOT_MARKER}
|
|
10
|
+
$(shell mkdir -p $(MARMOT_LOG_DIR)) ${MARMOT_MARKER}
|
|
11
|
+
$(shell marmot log make -d '{"target": "$(MAKECMDGOALS)"}' 2>/dev/null &) ${MARMOT_MARKER}`;
|
|
12
|
+
|
|
13
|
+
async function enable(projectConfig) {
|
|
14
|
+
const projectDir = process.cwd();
|
|
15
|
+
const makefilePath = path.join(projectDir, 'Makefile');
|
|
16
|
+
|
|
17
|
+
console.log('');
|
|
18
|
+
console.log(chalk.bold('Makefile Plugin Setup:'));
|
|
19
|
+
|
|
20
|
+
if (fs.existsSync(makefilePath)) {
|
|
21
|
+
const content = fs.readFileSync(makefilePath, 'utf8');
|
|
22
|
+
if (content.includes(MARMOT_MARKER)) {
|
|
23
|
+
console.log(chalk.yellow('Makefile already contains Marmot logging.'));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
console.log('Add the following to the top of your Makefile (after any initial comments):');
|
|
29
|
+
console.log('');
|
|
30
|
+
console.log(chalk.cyan(MAKEFILE_SNIPPET));
|
|
31
|
+
console.log('');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function disable(projectConfig) {
|
|
35
|
+
const projectDir = process.cwd();
|
|
36
|
+
const makefilePath = path.join(projectDir, 'Makefile');
|
|
37
|
+
|
|
38
|
+
console.log('');
|
|
39
|
+
console.log(chalk.bold('Makefile Plugin Disabled:'));
|
|
40
|
+
|
|
41
|
+
if (!fs.existsSync(makefilePath)) {
|
|
42
|
+
console.log('No Makefile found.');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const content = fs.readFileSync(makefilePath, 'utf8');
|
|
47
|
+
const lines = content.split('\n');
|
|
48
|
+
|
|
49
|
+
// Filter out lines ending with # marmot marker
|
|
50
|
+
const filteredLines = lines.filter(line => !line.trimEnd().endsWith(MARMOT_MARKER));
|
|
51
|
+
|
|
52
|
+
// Clean up multiple consecutive blank lines
|
|
53
|
+
const cleanedContent = filteredLines.join('\n')
|
|
54
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
55
|
+
.replace(/^\n+/, '');
|
|
56
|
+
|
|
57
|
+
if (content !== cleanedContent) {
|
|
58
|
+
fs.writeFileSync(makefilePath, cleanedContent);
|
|
59
|
+
console.log(chalk.green('Removed marmot logging lines from Makefile.'));
|
|
60
|
+
} else {
|
|
61
|
+
console.log('No marmot lines found in Makefile.');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
module.exports = {
|
|
66
|
+
enable,
|
|
67
|
+
disable
|
|
68
|
+
};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const config = require('../core/config');
|
|
6
|
+
|
|
7
|
+
const MARMOT_BASHRC_MARKER = '# marmot-terminal';
|
|
8
|
+
|
|
9
|
+
function getBashrcPath() {
|
|
10
|
+
return path.join(os.homedir(), '.bashrc');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function enable(projectConfig) {
|
|
14
|
+
const projectDir = process.cwd();
|
|
15
|
+
const marmotDir = config.getMarmotDir(projectDir);
|
|
16
|
+
const hookFile = path.join(marmotDir, 'terminal-hook.sh');
|
|
17
|
+
|
|
18
|
+
// Marmot dir should already exist from init, but ensure it does
|
|
19
|
+
if (!fs.existsSync(marmotDir)) {
|
|
20
|
+
fs.mkdirSync(marmotDir, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Generate bashrc hook script
|
|
24
|
+
const script = `#!/bin/bash
|
|
25
|
+
# Marmot Terminal Command Logging
|
|
26
|
+
# Source this file in your ~/.bashrc to log terminal commands
|
|
27
|
+
# Generated by: marmot enable terminal
|
|
28
|
+
|
|
29
|
+
MARMOT_PROJECT_DIR="${projectDir}"
|
|
30
|
+
|
|
31
|
+
if [[ -d "$MARMOT_PROJECT_DIR" ]]; then
|
|
32
|
+
__marmot_last_cmd=""
|
|
33
|
+
|
|
34
|
+
__marmot_log_command() {
|
|
35
|
+
local cmd=$(history 1 | sed 's/^ *[0-9]* *//')
|
|
36
|
+
|
|
37
|
+
# Skip if same as last command
|
|
38
|
+
[[ "$cmd" == "$__marmot_last_cmd" ]] && return
|
|
39
|
+
|
|
40
|
+
# Skip if empty
|
|
41
|
+
[[ -z "$cmd" ]] && return
|
|
42
|
+
|
|
43
|
+
# Only log if in project directory
|
|
44
|
+
if [[ "$PWD/" == "$MARMOT_PROJECT_DIR/"* || "$PWD" == "$MARMOT_PROJECT_DIR" ]]; then
|
|
45
|
+
(cd "$MARMOT_PROJECT_DIR" && marmot log terminal -d "{\\"command\\": \\"$cmd\\", \\"path\\": \\"$PWD\\"}" 2>/dev/null &) 2>/dev/null
|
|
46
|
+
__marmot_last_cmd="$cmd"
|
|
47
|
+
fi
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# Append to PROMPT_COMMAND
|
|
51
|
+
if [[ -z "$PROMPT_COMMAND" ]]; then
|
|
52
|
+
PROMPT_COMMAND="__marmot_log_command"
|
|
53
|
+
elif [[ "$PROMPT_COMMAND" != *"__marmot_log_command"* ]]; then
|
|
54
|
+
PROMPT_COMMAND="__marmot_log_command; $PROMPT_COMMAND"
|
|
55
|
+
fi
|
|
56
|
+
fi
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
fs.writeFileSync(hookFile, script);
|
|
60
|
+
fs.chmodSync(hookFile, '755');
|
|
61
|
+
|
|
62
|
+
// Add source line to ~/.bashrc
|
|
63
|
+
const bashrcPath = getBashrcPath();
|
|
64
|
+
const sourceLine = `source "${hookFile}" ${MARMOT_BASHRC_MARKER}`;
|
|
65
|
+
|
|
66
|
+
let bashrcUpdated = false;
|
|
67
|
+
if (fs.existsSync(bashrcPath)) {
|
|
68
|
+
const bashrcContent = fs.readFileSync(bashrcPath, 'utf8');
|
|
69
|
+
if (!bashrcContent.includes(hookFile)) {
|
|
70
|
+
fs.appendFileSync(bashrcPath, `\n${sourceLine}\n`);
|
|
71
|
+
bashrcUpdated = true;
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
fs.writeFileSync(bashrcPath, `${sourceLine}\n`);
|
|
75
|
+
bashrcUpdated = true;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
console.log('');
|
|
79
|
+
console.log(chalk.bold('Terminal Plugin Setup:'));
|
|
80
|
+
console.log(` Hook script: ${chalk.cyan(hookFile)}`);
|
|
81
|
+
|
|
82
|
+
if (bashrcUpdated) {
|
|
83
|
+
console.log(` Added to: ${chalk.cyan(bashrcPath)}`);
|
|
84
|
+
console.log('');
|
|
85
|
+
console.log('Reload your shell to activate:');
|
|
86
|
+
console.log(chalk.cyan(' source ~/.bashrc'));
|
|
87
|
+
} else {
|
|
88
|
+
console.log(` Already in: ${chalk.cyan(bashrcPath)}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function disable(projectConfig) {
|
|
93
|
+
const projectDir = process.cwd();
|
|
94
|
+
const marmotDir = config.getMarmotDir(projectDir);
|
|
95
|
+
const hookFile = path.join(marmotDir, 'terminal-hook.sh');
|
|
96
|
+
const bashrcPath = getBashrcPath();
|
|
97
|
+
|
|
98
|
+
console.log('');
|
|
99
|
+
console.log(chalk.bold('Terminal Plugin Disabled:'));
|
|
100
|
+
|
|
101
|
+
// Remove source line from ~/.bashrc
|
|
102
|
+
if (fs.existsSync(bashrcPath)) {
|
|
103
|
+
const bashrcContent = fs.readFileSync(bashrcPath, 'utf8');
|
|
104
|
+
const lines = bashrcContent.split('\n');
|
|
105
|
+
|
|
106
|
+
// Remove lines that source this hook file or have marmot marker
|
|
107
|
+
const filteredLines = lines.filter(line => {
|
|
108
|
+
const trimmed = line.trim();
|
|
109
|
+
if (trimmed.includes(hookFile)) return false;
|
|
110
|
+
if (trimmed.endsWith(MARMOT_BASHRC_MARKER)) return false;
|
|
111
|
+
return true;
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const newContent = filteredLines.join('\n').replace(/\n{3,}/g, '\n\n');
|
|
115
|
+
|
|
116
|
+
if (newContent !== bashrcContent) {
|
|
117
|
+
fs.writeFileSync(bashrcPath, newContent);
|
|
118
|
+
console.log(` Removed from: ${chalk.cyan(bashrcPath)}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Remove hook script file
|
|
123
|
+
if (fs.existsSync(hookFile)) {
|
|
124
|
+
fs.unlinkSync(hookFile);
|
|
125
|
+
console.log(` Removed: ${chalk.cyan(hookFile)}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
console.log('');
|
|
129
|
+
console.log('Reload your shell:');
|
|
130
|
+
console.log(chalk.cyan(' source ~/.bashrc'));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
module.exports = {
|
|
134
|
+
enable,
|
|
135
|
+
disable
|
|
136
|
+
};
|