junshi-tech-ai 1.0.1 → 1.0.3
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/dist/cli/install.d.ts.map +1 -1
- package/dist/cli/install.js +14 -5
- package/dist/cli/install.js.map +1 -1
- package/dist/runtime-bundle/index.d.ts +20 -0
- package/dist/runtime-bundle/index.d.ts.map +1 -0
- package/dist/runtime-bundle/index.js +48 -0
- package/dist/runtime-bundle/index.js.map +1 -0
- package/dist/runtime-bundle/logger.d.ts +34 -0
- package/dist/runtime-bundle/logger.d.ts.map +1 -0
- package/dist/runtime-bundle/logger.js +105 -0
- package/dist/runtime-bundle/logger.js.map +1 -0
- package/package.json +2 -1
- package/src/runtime-bundle/index.ts +82 -0
- package/src/runtime-bundle/logger.ts +147 -0
- package/src/runtime-bundle/package.json +9 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/cli/install.ts"],"names":[],"mappings":"AAmBA,wBAAsB,OAAO,
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/cli/install.ts"],"names":[],"mappings":"AAmBA,wBAAsB,OAAO,kBAgF5B"}
|
package/dist/cli/install.js
CHANGED
|
@@ -21,12 +21,21 @@ export async function install() {
|
|
|
21
21
|
await mkdir(pluginDir, { recursive: true });
|
|
22
22
|
await mkdir(logsDir, { recursive: true });
|
|
23
23
|
console.log('✅ Created directories');
|
|
24
|
-
// Step 3: Copy runtime files
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
// Step 3: Copy runtime files
|
|
25
|
+
// Try to find src/runtime first (for development), then fall back to bundled runtime
|
|
26
|
+
let runtimeSrc;
|
|
27
|
+
const devRuntimeSrc = join(__dirname, '../../src/runtime');
|
|
28
|
+
const bundledRuntimeSrc = join(__dirname, '../runtime-bundle');
|
|
29
|
+
if (existsSync(devRuntimeSrc)) {
|
|
30
|
+
runtimeSrc = devRuntimeSrc;
|
|
31
|
+
}
|
|
32
|
+
else if (existsSync(bundledRuntimeSrc)) {
|
|
33
|
+
runtimeSrc = bundledRuntimeSrc;
|
|
29
34
|
}
|
|
35
|
+
else {
|
|
36
|
+
throw new Error(`Runtime not found. Please check installation.`);
|
|
37
|
+
}
|
|
38
|
+
const runtimeDest = pluginDir;
|
|
30
39
|
// Copy individual files (not the whole directory)
|
|
31
40
|
const { readdir } = await import('node:fs/promises');
|
|
32
41
|
const files = await readdir(runtimeSrc);
|
package/dist/cli/install.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/cli/install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAM,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAa1D,MAAM,CAAC,KAAK,UAAU,OAAO;IAC3B,MAAM,OAAO,GAAG,OAAO,EAAE,CAAC;IAC1B,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC/C,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAEpD,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;IAErD,sCAAsC;IACtC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAE7C,6BAA6B;IAC7B,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IAErC,
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/cli/install.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-bundle/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-bundle/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-bundle/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-bundle/logger.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "junshi-tech-ai",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "OpenClaw Tool Hook - Log all tool calls to local file with rotation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cli/index.js",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"files": [
|
|
25
25
|
"dist",
|
|
26
|
+
"src/runtime-bundle",
|
|
26
27
|
"README.md"
|
|
27
28
|
],
|
|
28
29
|
"engines": {
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Runtime plugin for OpenClaw Tool Hook
|
|
2
|
+
// This file is loaded by OpenClaw as a plugin
|
|
3
|
+
|
|
4
|
+
import { RotatingLogger } from './logger.js';
|
|
5
|
+
|
|
6
|
+
const logger = new RotatingLogger();
|
|
7
|
+
|
|
8
|
+
interface PluginApi {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
pluginConfig?: Record<string, unknown>;
|
|
12
|
+
logger: {
|
|
13
|
+
info: (msg: string) => void;
|
|
14
|
+
warn: (msg: string) => void;
|
|
15
|
+
error: (msg: string) => void;
|
|
16
|
+
};
|
|
17
|
+
on: (hookName: string, handler: (event: unknown, ctx: unknown) => Promise<void>) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface ToolCallEvent {
|
|
21
|
+
toolName: string;
|
|
22
|
+
params: Record<string, unknown>;
|
|
23
|
+
toolCallId?: string;
|
|
24
|
+
runId?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface ToolResultEvent extends ToolCallEvent {
|
|
28
|
+
result?: unknown;
|
|
29
|
+
error?: string;
|
|
30
|
+
durationMs?: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const plugin = {
|
|
34
|
+
id: 'tool-logger',
|
|
35
|
+
name: 'Tool Logger',
|
|
36
|
+
version: '1.0.0',
|
|
37
|
+
description: 'Log all OpenClaw tool calls to local file with rotation',
|
|
38
|
+
|
|
39
|
+
register(api: PluginApi) {
|
|
40
|
+
// Get plugin config
|
|
41
|
+
const config = api.pluginConfig || {};
|
|
42
|
+
const logPath = config.logPath as string | undefined;
|
|
43
|
+
const maxFileSize = config.maxFileSize as number | undefined;
|
|
44
|
+
const maxFiles = config.maxFiles as number | undefined;
|
|
45
|
+
|
|
46
|
+
// Initialize logger with config
|
|
47
|
+
logger.initialize(logPath, maxFileSize, maxFiles);
|
|
48
|
+
|
|
49
|
+
api.logger.info('Tool Logger plugin registered');
|
|
50
|
+
|
|
51
|
+
// Hook: Before tool call
|
|
52
|
+
api.on('before_tool_call', async (eventRaw: unknown) => {
|
|
53
|
+
const event = eventRaw as ToolCallEvent;
|
|
54
|
+
await logger.logCall({
|
|
55
|
+
timestamp: Date.now(),
|
|
56
|
+
toolName: event.toolName,
|
|
57
|
+
params: event.params,
|
|
58
|
+
toolCallId: event.toolCallId,
|
|
59
|
+
runId: event.runId,
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Hook: After tool call
|
|
64
|
+
api.on('after_tool_call', async (eventRaw: unknown) => {
|
|
65
|
+
const event = eventRaw as ToolResultEvent;
|
|
66
|
+
await logger.logResult({
|
|
67
|
+
timestamp: Date.now(),
|
|
68
|
+
toolName: event.toolName,
|
|
69
|
+
params: event.params,
|
|
70
|
+
toolCallId: event.toolCallId,
|
|
71
|
+
runId: event.runId,
|
|
72
|
+
result: event.result,
|
|
73
|
+
error: event.error,
|
|
74
|
+
durationMs: event.durationMs,
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
api.logger.info('Tool Logger hooks registered successfully');
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export default plugin;
|
|
@@ -0,0 +1,147 @@
|
|
|
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, mkdir } from 'node:fs/promises';
|
|
5
|
+
|
|
6
|
+
interface ToolCallRecord {
|
|
7
|
+
timestamp: number;
|
|
8
|
+
toolName: string;
|
|
9
|
+
params: Record<string, unknown>;
|
|
10
|
+
toolCallId?: string;
|
|
11
|
+
runId?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ToolResultRecord {
|
|
15
|
+
timestamp: number;
|
|
16
|
+
toolName: string;
|
|
17
|
+
params: Record<string, unknown>;
|
|
18
|
+
toolCallId?: string;
|
|
19
|
+
runId?: string;
|
|
20
|
+
result?: unknown;
|
|
21
|
+
error?: string;
|
|
22
|
+
durationMs?: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type LogRecord =
|
|
26
|
+
| ({ type: 'call' } & ToolCallRecord)
|
|
27
|
+
| ({ type: 'result' } & ToolResultRecord);
|
|
28
|
+
|
|
29
|
+
export class RotatingLogger {
|
|
30
|
+
private logPath: string = '';
|
|
31
|
+
private maxFileSize: number = 10 * 1024 * 1024; // 10MB
|
|
32
|
+
private maxFiles: number = 5;
|
|
33
|
+
private stream: ReturnType<typeof createWriteStream> | null = null;
|
|
34
|
+
private currentSize: number = 0;
|
|
35
|
+
private initialized: boolean = false;
|
|
36
|
+
|
|
37
|
+
initialize(logPath?: string, maxFileSize?: number, maxFiles?: number) {
|
|
38
|
+
if (this.initialized) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.logPath = logPath || join(homedir(), '.openclaw/logs/tool-calls.jsonl');
|
|
43
|
+
this.maxFileSize = maxFileSize || this.maxFileSize;
|
|
44
|
+
this.maxFiles = maxFiles || this.maxFiles;
|
|
45
|
+
|
|
46
|
+
// Ensure directory exists
|
|
47
|
+
const logDir = dirname(this.logPath);
|
|
48
|
+
if (!existsSync(logDir)) {
|
|
49
|
+
mkdirSync(logDir, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Get current file size if exists
|
|
53
|
+
if (existsSync(this.logPath)) {
|
|
54
|
+
this.currentSize = statSync(this.logPath).size;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Create write stream
|
|
58
|
+
this.stream = createWriteStream(this.logPath, { flags: 'a' });
|
|
59
|
+
this.initialized = true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async logCall(record: ToolCallRecord): Promise<void> {
|
|
63
|
+
if (!this.initialized) {
|
|
64
|
+
this.initialize();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const logRecord: LogRecord = { type: 'call', ...record };
|
|
68
|
+
await this.write(logRecord);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async logResult(record: ToolResultRecord): Promise<void> {
|
|
72
|
+
if (!this.initialized) {
|
|
73
|
+
this.initialize();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const logRecord: LogRecord = { type: 'result', ...record };
|
|
77
|
+
await this.write(logRecord);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private async write(record: LogRecord): Promise<void> {
|
|
81
|
+
if (!this.stream) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const line = JSON.stringify(record) + '\n';
|
|
86
|
+
const lineSize = Buffer.byteLength(line, 'utf-8');
|
|
87
|
+
|
|
88
|
+
// Check if rotation is needed
|
|
89
|
+
if (this.currentSize + lineSize > this.maxFileSize) {
|
|
90
|
+
await this.rotate();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Write to stream
|
|
94
|
+
this.stream.write(line);
|
|
95
|
+
this.currentSize += lineSize;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private async rotate(): Promise<void> {
|
|
99
|
+
if (!this.stream) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Close current stream
|
|
104
|
+
this.stream.end();
|
|
105
|
+
this.stream = null;
|
|
106
|
+
|
|
107
|
+
// Rotate files
|
|
108
|
+
await this.rotateFiles();
|
|
109
|
+
|
|
110
|
+
// Create new stream
|
|
111
|
+
this.stream = createWriteStream(this.logPath, { flags: 'a' });
|
|
112
|
+
this.currentSize = 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private async rotateFiles(): Promise<void> {
|
|
116
|
+
// Delete oldest file if it exists
|
|
117
|
+
const oldestFile = `${this.logPath}.${this.maxFiles - 1}`;
|
|
118
|
+
if (existsSync(oldestFile)) {
|
|
119
|
+
try {
|
|
120
|
+
await writeFile(oldestFile, ''); // Truncate instead of delete to keep file handle
|
|
121
|
+
} catch {
|
|
122
|
+
// Ignore errors
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Shift files
|
|
127
|
+
for (let i = this.maxFiles - 2; i >= 0; i--) {
|
|
128
|
+
const src = i === 0 ? this.logPath : `${this.logPath}.${i}`;
|
|
129
|
+
const dest = `${this.logPath}.${i + 1}`;
|
|
130
|
+
|
|
131
|
+
if (existsSync(src)) {
|
|
132
|
+
try {
|
|
133
|
+
renameSync(src, dest);
|
|
134
|
+
} catch {
|
|
135
|
+
// Ignore errors
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
close(): void {
|
|
142
|
+
if (this.stream) {
|
|
143
|
+
this.stream.end();
|
|
144
|
+
this.stream = null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|