junshi-tech-ai 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 ADDED
@@ -0,0 +1,132 @@
1
+ # OpenClaw Tool Hook
2
+
3
+ Log all OpenClaw tool calls to a local file with automatic rotation.
4
+
5
+ ## Features
6
+
7
+ - ✅ Logs all tool calls (before and after execution)
8
+ - ✅ Automatic log rotation (configurable size and file count)
9
+ - ✅ JSONL format for easy parsing
10
+ - ✅ Zero configuration required
11
+ - ✅ No sensitive data filtering (logs everything)
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ # Install the CLI tool globally
17
+ npm install -g junshi-tech-ai
18
+
19
+ # Install the plugin
20
+ openclaw-tool-hook install
21
+
22
+ # Restart OpenClaw
23
+ openclaw gateway restart
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ### Check Status
29
+
30
+ ```bash
31
+ openclaw-tool-hook status
32
+ ```
33
+
34
+ ### View Logs
35
+
36
+ Logs are stored in `~/.openclaw/logs/tool-calls.jsonl`
37
+
38
+ ```bash
39
+ # View latest logs
40
+ tail -f ~/.openclaw/logs/tool-calls.jsonl
41
+
42
+ # Search for specific tool
43
+ grep '"toolName":"exec"' ~/.openclaw/logs/tool-calls.jsonl
44
+ ```
45
+
46
+ ### Uninstall
47
+
48
+ ```bash
49
+ openclaw-tool-hook uninstall
50
+ openclaw gateway restart
51
+ ```
52
+
53
+ ## Log Format
54
+
55
+ Each line is a JSON object:
56
+
57
+ ### Tool Call Record
58
+
59
+ ```json
60
+ {
61
+ "type": "call",
62
+ "timestamp": 1710147600000,
63
+ "toolName": "exec",
64
+ "params": { "command": "ls -la" },
65
+ "toolCallId": "call-123",
66
+ "runId": "run-456"
67
+ }
68
+ ```
69
+
70
+ ### Tool Result Record
71
+
72
+ ```json
73
+ {
74
+ "type": "result",
75
+ "timestamp": 1710147600123,
76
+ "toolName": "exec",
77
+ "params": { "command": "ls -la" },
78
+ "toolCallId": "call-123",
79
+ "runId": "run-456",
80
+ "result": "total 48...",
81
+ "durationMs": 123
82
+ }
83
+ ```
84
+
85
+ ## Configuration
86
+
87
+ Edit `~/.openclaw/config.json`:
88
+
89
+ ```json
90
+ {
91
+ "plugins": {
92
+ "entries": {
93
+ "tool-logger": {
94
+ "enabled": true,
95
+ "config": {
96
+ "logPath": "~/.openclaw/logs/tool-calls.jsonl",
97
+ "maxFileSize": 10485760,
98
+ "maxFiles": 5
99
+ }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ ```
105
+
106
+ - `logPath`: Path to log file (default: `~/.openclaw/logs/tool-calls.jsonl`)
107
+ - `maxFileSize`: Max file size in bytes before rotation (default: 10MB)
108
+ - `maxFiles`: Number of rotated files to keep (default: 5)
109
+
110
+ ## Log Rotation
111
+
112
+ When the log file reaches `maxFileSize`, it rotates:
113
+
114
+ ```
115
+ tool-calls.jsonl # Current log
116
+ tool-calls.jsonl.1 # Previous log
117
+ tool-calls.jsonl.2 # Older log
118
+ ...
119
+ tool-calls.jsonl.4 # Oldest log
120
+ ```
121
+
122
+ ## License
123
+
124
+ MIT
125
+
126
+ ## Package
127
+
128
+ **NPM Package**: `junshi-tech-ai`
129
+
130
+ ```bash
131
+ npm install -g junshi-tech-ai
132
+ ```
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env node
2
+ import { install } from './install.js';
3
+ import { uninstall } from './uninstall.js';
4
+ import { status } from './status.js';
5
+ const command = process.argv[2];
6
+ async function main() {
7
+ try {
8
+ switch (command) {
9
+ case 'install':
10
+ await install();
11
+ break;
12
+ case 'uninstall':
13
+ await uninstall();
14
+ break;
15
+ case 'status':
16
+ await status();
17
+ break;
18
+ case 'help':
19
+ case '--help':
20
+ case '-h':
21
+ printHelp();
22
+ break;
23
+ case undefined:
24
+ printHelp();
25
+ break;
26
+ default:
27
+ console.error(`❌ Unknown command: ${command}`);
28
+ printHelp();
29
+ process.exit(1);
30
+ }
31
+ }
32
+ catch (error) {
33
+ console.error(`❌ Error: ${error instanceof Error ? error.message : error}`);
34
+ process.exit(1);
35
+ }
36
+ }
37
+ function printHelp() {
38
+ console.log(`
39
+ OpenClaw Tool Hook - Log all tool calls
40
+
41
+ Usage:
42
+ openclaw-tool-hook <command>
43
+
44
+ Commands:
45
+ install Install the tool hook plugin
46
+ uninstall Remove the tool hook plugin
47
+ status Check installation status
48
+ help Show this help message
49
+
50
+ Examples:
51
+ openclaw-tool-hook install # Install and enable tool logging
52
+ openclaw-tool-hook status # Check if installed
53
+ openclaw-tool-hook uninstall # Remove the hook
54
+ `);
55
+ }
56
+ main();
57
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAEhC,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,QAAQ,OAAO,EAAE,CAAC;YAChB,KAAK,SAAS;gBACZ,MAAM,OAAO,EAAE,CAAC;gBAChB,MAAM;YACR,KAAK,WAAW;gBACd,MAAM,SAAS,EAAE,CAAC;gBAClB,MAAM;YACR,KAAK,QAAQ;gBACX,MAAM,MAAM,EAAE,CAAC;gBACf,MAAM;YACR,KAAK,MAAM,CAAC;YACZ,KAAK,QAAQ,CAAC;YACd,KAAK,IAAI;gBACP,SAAS,EAAE,CAAC;gBACZ,MAAM;YACR,KAAK,SAAS;gBACZ,SAAS,EAAE,CAAC;gBACZ,MAAM;YACR;gBACE,OAAO,CAAC,KAAK,CAAC,sBAAsB,OAAO,EAAE,CAAC,CAAC;gBAC/C,SAAS,EAAE,CAAC;gBACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,YAAY,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;QAC5E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;CAgBb,CAAC,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function install(): Promise<void>;
2
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/cli/install.ts"],"names":[],"mappings":"AAmBA,wBAAsB,OAAO,kBA6D5B"}
@@ -0,0 +1,103 @@
1
+ import { homedir } from 'node:os';
2
+ import { join, dirname } from 'node:path';
3
+ import { mkdir, writeFile, readFile, cp } from 'node:fs/promises';
4
+ import { existsSync } from 'node:fs';
5
+ import { fileURLToPath } from 'node:url';
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ export async function install() {
8
+ const homeDir = homedir();
9
+ const openclawDir = join(homeDir, '.openclaw');
10
+ const extensionsDir = join(openclawDir, 'extensions');
11
+ const pluginDir = join(extensionsDir, 'tool-logger');
12
+ const logsDir = join(openclawDir, 'logs');
13
+ const configPath = join(openclawDir, 'config.json');
14
+ console.log('🔧 Installing OpenClaw Tool Hook...\n');
15
+ // Step 1: Check OpenClaw installation
16
+ if (!existsSync(openclawDir)) {
17
+ throw new Error('OpenClaw not found. Please install OpenClaw first.');
18
+ }
19
+ console.log('✅ OpenClaw installation found');
20
+ // Step 2: Create directories
21
+ await mkdir(pluginDir, { recursive: true });
22
+ await mkdir(logsDir, { recursive: true });
23
+ console.log('✅ Created directories');
24
+ // Step 3: Copy runtime files
25
+ const runtimeSrc = join(__dirname, '../runtime');
26
+ const runtimeDest = join(pluginDir, 'dist');
27
+ if (!existsSync(runtimeSrc)) {
28
+ throw new Error(`Runtime not found at ${runtimeSrc}. Please build the package first.`);
29
+ }
30
+ await cp(runtimeSrc, runtimeDest, { recursive: true });
31
+ console.log('✅ Copied runtime files');
32
+ // Step 4: Create plugin package.json
33
+ const pluginPackageJson = {
34
+ name: 'tool-logger-runtime',
35
+ version: '1.0.0',
36
+ type: 'module',
37
+ main: 'dist/index.js'
38
+ };
39
+ await writeFile(join(pluginDir, 'package.json'), JSON.stringify(pluginPackageJson, null, 2));
40
+ console.log('✅ Created plugin manifest');
41
+ // Step 5: Update OpenClaw config
42
+ await updateConfig(configPath, true);
43
+ console.log('✅ Updated OpenClaw configuration');
44
+ // Step 6: Create initial log file
45
+ const logPath = join(logsDir, 'tool-calls.jsonl');
46
+ if (!existsSync(logPath)) {
47
+ await writeFile(logPath, '', 'utf-8');
48
+ }
49
+ console.log('✅ Created log file');
50
+ console.log('\n✅ Tool Hook installed successfully!\n');
51
+ console.log('📝 Log file: ~/.openclaw/logs/tool-calls.jsonl');
52
+ console.log('📁 Log directory: ~/.openclaw/logs/');
53
+ console.log('\n🔄 Please restart OpenClaw to enable the hook:');
54
+ console.log(' openclaw gateway restart\n');
55
+ }
56
+ async function updateConfig(configPath, enable) {
57
+ let config = { entries: {}, installs: {} };
58
+ if (existsSync(configPath)) {
59
+ try {
60
+ const content = await readFile(configPath, 'utf-8');
61
+ const parsed = JSON.parse(content);
62
+ config = {
63
+ entries: parsed.plugins?.entries || {},
64
+ installs: parsed.plugins?.installs || {}
65
+ };
66
+ }
67
+ catch (error) {
68
+ console.warn('⚠️ Could not parse existing config, creating new one');
69
+ }
70
+ }
71
+ if (enable) {
72
+ config.entries = config.entries || {};
73
+ config.entries['tool-logger'] = {
74
+ enabled: true,
75
+ config: {
76
+ logPath: join(homedir(), '.openclaw/logs/tool-calls.jsonl'),
77
+ maxFileSize: 10 * 1024 * 1024, // 10MB
78
+ maxFiles: 5
79
+ }
80
+ };
81
+ config.installs = config.installs || {};
82
+ config.installs['tool-logger'] = {
83
+ source: 'npm',
84
+ spec: 'junshi-tech-ai',
85
+ installPath: join(homedir(), '.openclaw/extensions/tool-logger'),
86
+ version: '1.0.0',
87
+ installedAt: new Date().toISOString()
88
+ };
89
+ }
90
+ else {
91
+ if (config.entries) {
92
+ delete config.entries['tool-logger'];
93
+ }
94
+ if (config.installs) {
95
+ delete config.installs['tool-logger'];
96
+ }
97
+ }
98
+ const finalConfig = {
99
+ plugins: config
100
+ };
101
+ await writeFile(configPath, JSON.stringify(finalConfig, null, 2), 'utf-8');
102
+ }
103
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/cli/install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function status(): Promise<void>;
2
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/cli/status.ts"],"names":[],"mappings":"AAOA,wBAAsB,MAAM,kBA0D3B"}
@@ -0,0 +1,70 @@
1
+ import { homedir } from 'node:os';
2
+ import { join } from 'node:path';
3
+ import { readFile } from 'node:fs/promises';
4
+ import { existsSync } from 'node:fs';
5
+ export async function status() {
6
+ const homeDir = homedir();
7
+ const openclawDir = join(homeDir, '.openclaw');
8
+ const pluginDir = join(openclawDir, 'extensions/tool-logger');
9
+ const configPath = join(openclawDir, 'config.json');
10
+ const logsDir = join(openclawDir, 'logs');
11
+ console.log('📊 OpenClaw Tool Hook Status\n');
12
+ // Check plugin installation
13
+ const pluginInstalled = existsSync(pluginDir);
14
+ console.log(`${pluginInstalled ? '✅' : '❌'} Plugin installed: ${pluginInstalled ? 'Yes' : 'No'}`);
15
+ // Check config
16
+ let configEnabled = false;
17
+ if (existsSync(configPath)) {
18
+ try {
19
+ const content = await readFile(configPath, 'utf-8');
20
+ const config = JSON.parse(content);
21
+ configEnabled = config.plugins?.entries?.['tool-logger']?.enabled ?? false;
22
+ }
23
+ catch {
24
+ configEnabled = false;
25
+ }
26
+ }
27
+ console.log(`${configEnabled ? '✅' : '❌'} Plugin enabled in config: ${configEnabled ? 'Yes' : 'No'}`);
28
+ // Check log files
29
+ console.log('\n📁 Log Files:');
30
+ if (existsSync(logsDir)) {
31
+ const logFiles = await getLogFiles(logsDir);
32
+ if (logFiles.length > 0) {
33
+ for (const file of logFiles) {
34
+ const stats = await readFile(join(logsDir, file));
35
+ const lines = stats.toString().split('\n').filter(l => l.trim()).length;
36
+ const sizeKB = Math.round(stats.length / 1024);
37
+ console.log(` 📄 ${file} (${lines} lines, ${sizeKB}KB)`);
38
+ }
39
+ }
40
+ else {
41
+ console.log(' ℹ️ No log files found');
42
+ }
43
+ }
44
+ else {
45
+ console.log(' ℹ️ Logs directory not found');
46
+ }
47
+ // Overall status
48
+ console.log('\n' + '='.repeat(50));
49
+ if (pluginInstalled && configEnabled) {
50
+ console.log('✅ Tool Hook is ACTIVE and ready to log tool calls');
51
+ }
52
+ else {
53
+ console.log('❌ Tool Hook is NOT ACTIVE');
54
+ if (!pluginInstalled) {
55
+ console.log(' → Run: openclaw-tool-hook install');
56
+ }
57
+ if (!configEnabled) {
58
+ console.log(' → Run: openclaw-tool-hook install');
59
+ }
60
+ }
61
+ console.log('='.repeat(50) + '\n');
62
+ }
63
+ async function getLogFiles(logsDir) {
64
+ const { readdir } = await import('node:fs/promises');
65
+ const files = await readdir(logsDir);
66
+ return files
67
+ .filter(f => f.startsWith('tool-calls'))
68
+ .sort();
69
+ }
70
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/cli/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function uninstall(): Promise<void>;
2
+ //# sourceMappingURL=uninstall.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uninstall.d.ts","sourceRoot":"","sources":["../../src/cli/uninstall.ts"],"names":[],"mappings":"AAKA,wBAAsB,SAAS,kBA6B9B"}
@@ -0,0 +1,53 @@
1
+ import { homedir } from 'node:os';
2
+ import { join } from 'node:path';
3
+ import { readFile, writeFile } from 'node:fs/promises';
4
+ import { existsSync } from 'node:fs';
5
+ export async function uninstall() {
6
+ const homeDir = homedir();
7
+ const openclawDir = join(homeDir, '.openclaw');
8
+ const pluginDir = join(openclawDir, 'extensions/tool-logger');
9
+ const configPath = join(openclawDir, 'config.json');
10
+ console.log('🔧 Uninstalling OpenClaw Tool Hook...\n');
11
+ // Step 1: Remove plugin directory
12
+ if (existsSync(pluginDir)) {
13
+ await import('node:fs/promises').then(({ rm }) => rm(pluginDir, { recursive: true, force: true }));
14
+ console.log('✅ Removed plugin directory');
15
+ }
16
+ else {
17
+ console.log('ℹ️ Plugin directory not found, skipping');
18
+ }
19
+ // Step 2: Update OpenClaw config
20
+ if (existsSync(configPath)) {
21
+ await updateConfig(configPath, false);
22
+ console.log('✅ Updated OpenClaw configuration');
23
+ }
24
+ else {
25
+ console.log('ℹ️ Config file not found, skipping');
26
+ }
27
+ console.log('\n✅ Tool Hook uninstalled successfully!\n');
28
+ console.log('📝 Log files are preserved in ~/.openclaw/logs/');
29
+ console.log(' To remove logs: rm -rf ~/.openclaw/logs/tool-calls*\n');
30
+ console.log('🔄 Please restart OpenClaw:');
31
+ console.log(' openclaw gateway restart\n');
32
+ }
33
+ async function updateConfig(configPath, enable) {
34
+ let config = { plugins: { entries: {}, installs: {} } };
35
+ try {
36
+ const content = await readFile(configPath, 'utf-8');
37
+ config = JSON.parse(content);
38
+ }
39
+ catch {
40
+ console.warn('⚠️ Could not parse config, creating new one');
41
+ }
42
+ const plugins = config.plugins;
43
+ if (plugins?.entries && typeof plugins.entries === 'object') {
44
+ const entries = plugins.entries;
45
+ delete entries['tool-logger'];
46
+ }
47
+ if (plugins?.installs && typeof plugins.installs === 'object') {
48
+ const installs = plugins.installs;
49
+ delete installs['tool-logger'];
50
+ }
51
+ await writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');
52
+ }
53
+ //# sourceMappingURL=uninstall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uninstall.js","sourceRoot":"","sources":["../../src/cli/uninstall.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ interface PluginApi {
2
+ id: string;
3
+ name: string;
4
+ pluginConfig?: Record<string, unknown>;
5
+ logger: {
6
+ info: (msg: string) => void;
7
+ warn: (msg: string) => void;
8
+ error: (msg: string) => void;
9
+ };
10
+ on: (hookName: string, handler: (event: unknown, ctx: unknown) => Promise<void>) => void;
11
+ }
12
+ declare const plugin: {
13
+ id: string;
14
+ name: string;
15
+ version: string;
16
+ description: string;
17
+ register(api: PluginApi): void;
18
+ };
19
+ export default plugin;
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAOA,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,MAAM,EAAE;QACN,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5B,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;KAC9B,CAAC;IACF,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;CAC1F;AAeD,QAAA,MAAM,MAAM;;;;;kBAMI,SAAS;CAyCxB,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -0,0 +1,48 @@
1
+ // Runtime plugin for OpenClaw Tool Hook
2
+ // This file is loaded by OpenClaw as a plugin
3
+ import { RotatingLogger } from './logger.js';
4
+ const logger = new RotatingLogger();
5
+ const plugin = {
6
+ id: 'tool-logger',
7
+ name: 'Tool Logger',
8
+ version: '1.0.0',
9
+ description: 'Log all OpenClaw tool calls to local file with rotation',
10
+ register(api) {
11
+ // Get plugin config
12
+ const config = api.pluginConfig || {};
13
+ const logPath = config.logPath;
14
+ const maxFileSize = config.maxFileSize;
15
+ const maxFiles = config.maxFiles;
16
+ // Initialize logger with config
17
+ logger.initialize(logPath, maxFileSize, maxFiles);
18
+ api.logger.info('Tool Logger plugin registered');
19
+ // Hook: Before tool call
20
+ api.on('before_tool_call', async (eventRaw) => {
21
+ const event = eventRaw;
22
+ await logger.logCall({
23
+ timestamp: Date.now(),
24
+ toolName: event.toolName,
25
+ params: event.params,
26
+ toolCallId: event.toolCallId,
27
+ runId: event.runId,
28
+ });
29
+ });
30
+ // Hook: After tool call
31
+ api.on('after_tool_call', async (eventRaw) => {
32
+ const event = eventRaw;
33
+ await logger.logResult({
34
+ timestamp: Date.now(),
35
+ toolName: event.toolName,
36
+ params: event.params,
37
+ toolCallId: event.toolCallId,
38
+ runId: event.runId,
39
+ result: event.result,
40
+ error: event.error,
41
+ durationMs: event.durationMs,
42
+ });
43
+ });
44
+ api.logger.info('Tool Logger hooks registered successfully');
45
+ }
46
+ };
47
+ export default plugin;
48
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,8CAA8C;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;AA2BpC,MAAM,MAAM,GAAG;IACb,EAAE,EAAE,aAAa;IACjB,IAAI,EAAE,aAAa;IACnB,OAAO,EAAE,OAAO;IAChB,WAAW,EAAE,yDAAyD;IAEtE,QAAQ,CAAC,GAAc;QACrB,oBAAoB;QACpB,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC;QACtC,MAAM,OAAO,GAAG,MAAM,CAAC,OAA6B,CAAC;QACrD,MAAM,WAAW,GAAG,MAAM,CAAC,WAAiC,CAAC;QAC7D,MAAM,QAAQ,GAAG,MAAM,CAAC,QAA8B,CAAC;QAEvD,gCAAgC;QAChC,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;QAElD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAEjD,yBAAyB;QACzB,GAAG,CAAC,EAAE,CAAC,kBAAkB,EAAE,KAAK,EAAE,QAAiB,EAAE,EAAE;YACrD,MAAM,KAAK,GAAG,QAAyB,CAAC;YACxC,MAAM,MAAM,CAAC,OAAO,CAAC;gBACnB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;gBACrB,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,KAAK,EAAE,KAAK,CAAC,KAAK;aACnB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,wBAAwB;QACxB,GAAG,CAAC,EAAE,CAAC,iBAAiB,EAAE,KAAK,EAAE,QAAiB,EAAE,EAAE;YACpD,MAAM,KAAK,GAAG,QAA2B,CAAC;YAC1C,MAAM,MAAM,CAAC,SAAS,CAAC;gBACrB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;gBACrB,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,UAAU,EAAE,KAAK,CAAC,UAAU;aAC7B,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;CACF,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -0,0 +1,34 @@
1
+ interface ToolCallRecord {
2
+ timestamp: number;
3
+ toolName: string;
4
+ params: Record<string, unknown>;
5
+ toolCallId?: string;
6
+ runId?: string;
7
+ }
8
+ interface ToolResultRecord {
9
+ timestamp: number;
10
+ toolName: string;
11
+ params: Record<string, unknown>;
12
+ toolCallId?: string;
13
+ runId?: string;
14
+ result?: unknown;
15
+ error?: string;
16
+ durationMs?: number;
17
+ }
18
+ export declare class RotatingLogger {
19
+ private logPath;
20
+ private maxFileSize;
21
+ private maxFiles;
22
+ private stream;
23
+ private currentSize;
24
+ private initialized;
25
+ initialize(logPath?: string, maxFileSize?: number, maxFiles?: number): void;
26
+ logCall(record: ToolCallRecord): Promise<void>;
27
+ logResult(record: ToolResultRecord): Promise<void>;
28
+ private write;
29
+ private rotate;
30
+ private rotateFiles;
31
+ close(): void;
32
+ }
33
+ export {};
34
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/runtime/logger.ts"],"names":[],"mappings":"AAKA,UAAU,cAAc;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,gBAAgB;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,MAAM,CAAqD;IACnE,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,WAAW,CAAkB;IAErC,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;IAyB9D,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAS9C,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;YAS1C,KAAK;YAkBL,MAAM;YAiBN,WAAW;IA0BzB,KAAK,IAAI,IAAI;CAMd"}
@@ -0,0 +1,105 @@
1
+ import { homedir } from 'node:os';
2
+ import { join, dirname } from 'node:path';
3
+ import { createWriteStream, existsSync, statSync, renameSync, mkdirSync } from 'node:fs';
4
+ import { writeFile } from 'node:fs/promises';
5
+ export class RotatingLogger {
6
+ logPath = '';
7
+ maxFileSize = 10 * 1024 * 1024; // 10MB
8
+ maxFiles = 5;
9
+ stream = null;
10
+ currentSize = 0;
11
+ initialized = false;
12
+ initialize(logPath, maxFileSize, maxFiles) {
13
+ if (this.initialized) {
14
+ return;
15
+ }
16
+ this.logPath = logPath || join(homedir(), '.openclaw/logs/tool-calls.jsonl');
17
+ this.maxFileSize = maxFileSize || this.maxFileSize;
18
+ this.maxFiles = maxFiles || this.maxFiles;
19
+ // Ensure directory exists
20
+ const logDir = dirname(this.logPath);
21
+ if (!existsSync(logDir)) {
22
+ mkdirSync(logDir, { recursive: true });
23
+ }
24
+ // Get current file size if exists
25
+ if (existsSync(this.logPath)) {
26
+ this.currentSize = statSync(this.logPath).size;
27
+ }
28
+ // Create write stream
29
+ this.stream = createWriteStream(this.logPath, { flags: 'a' });
30
+ this.initialized = true;
31
+ }
32
+ async logCall(record) {
33
+ if (!this.initialized) {
34
+ this.initialize();
35
+ }
36
+ const logRecord = { type: 'call', ...record };
37
+ await this.write(logRecord);
38
+ }
39
+ async logResult(record) {
40
+ if (!this.initialized) {
41
+ this.initialize();
42
+ }
43
+ const logRecord = { type: 'result', ...record };
44
+ await this.write(logRecord);
45
+ }
46
+ async write(record) {
47
+ if (!this.stream) {
48
+ return;
49
+ }
50
+ const line = JSON.stringify(record) + '\n';
51
+ const lineSize = Buffer.byteLength(line, 'utf-8');
52
+ // Check if rotation is needed
53
+ if (this.currentSize + lineSize > this.maxFileSize) {
54
+ await this.rotate();
55
+ }
56
+ // Write to stream
57
+ this.stream.write(line);
58
+ this.currentSize += lineSize;
59
+ }
60
+ async rotate() {
61
+ if (!this.stream) {
62
+ return;
63
+ }
64
+ // Close current stream
65
+ this.stream.end();
66
+ this.stream = null;
67
+ // Rotate files
68
+ await this.rotateFiles();
69
+ // Create new stream
70
+ this.stream = createWriteStream(this.logPath, { flags: 'a' });
71
+ this.currentSize = 0;
72
+ }
73
+ async rotateFiles() {
74
+ // Delete oldest file if it exists
75
+ const oldestFile = `${this.logPath}.${this.maxFiles - 1}`;
76
+ if (existsSync(oldestFile)) {
77
+ try {
78
+ await writeFile(oldestFile, ''); // Truncate instead of delete to keep file handle
79
+ }
80
+ catch {
81
+ // Ignore errors
82
+ }
83
+ }
84
+ // Shift files
85
+ for (let i = this.maxFiles - 2; i >= 0; i--) {
86
+ const src = i === 0 ? this.logPath : `${this.logPath}.${i}`;
87
+ const dest = `${this.logPath}.${i + 1}`;
88
+ if (existsSync(src)) {
89
+ try {
90
+ renameSync(src, dest);
91
+ }
92
+ catch {
93
+ // Ignore errors
94
+ }
95
+ }
96
+ }
97
+ }
98
+ close() {
99
+ if (this.stream) {
100
+ this.stream.end();
101
+ this.stream = null;
102
+ }
103
+ }
104
+ }
105
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/runtime/logger.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "junshi-tech-ai",
3
+ "version": "1.0.0",
4
+ "description": "OpenClaw Tool Hook - Log all tool calls to local file with rotation",
5
+ "type": "module",
6
+ "main": "dist/cli/index.js",
7
+ "bin": {
8
+ "openclaw-tool-hook": "dist/cli/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "prepublishOnly": "npm run build",
13
+ "test": "echo \"No tests yet\""
14
+ },
15
+ "keywords": [
16
+ "openclaw",
17
+ "tool",
18
+ "hook",
19
+ "logger",
20
+ "audit"
21
+ ],
22
+ "author": "Junshi",
23
+ "license": "MIT",
24
+ "files": [
25
+ "dist",
26
+ "README.md"
27
+ ],
28
+ "engines": {
29
+ "node": ">=18.0.0"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^20.10.0",
33
+ "typescript": "^5.3.0"
34
+ }
35
+ }