@spzhongwin/skill-logger-plugin 1.0.13 → 1.0.14
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/index.js +45 -2
- package/package.json +1 -1
- package/src/ws-client.test.ts +80 -0
- package/src/ws-client.ts +55 -3
package/dist/index.js
CHANGED
|
@@ -1638,6 +1638,7 @@ var Reporter = class {
|
|
|
1638
1638
|
import WebSocket from "ws";
|
|
1639
1639
|
import path7 from "path";
|
|
1640
1640
|
import fs6 from "fs/promises";
|
|
1641
|
+
import { DatabaseSync } from "node:sqlite";
|
|
1641
1642
|
var HEARTBEAT_INTERVAL_MS = 3e4;
|
|
1642
1643
|
var HEARTBEAT_ACK_TIMEOUT_MS = 75e3;
|
|
1643
1644
|
var AGENT_SCAN_INTERVAL_MS = 3 * 60 * 1e3;
|
|
@@ -1660,6 +1661,21 @@ function normalizeAssistantUserId(userId) {
|
|
|
1660
1661
|
function shouldSyncBuiltInTemplate(action, isBuiltIn) {
|
|
1661
1662
|
return action === "UPDATE_SKILL" && isBuiltIn === true;
|
|
1662
1663
|
}
|
|
1664
|
+
function defaultOpenclawSqlitePath() {
|
|
1665
|
+
return path7.join(openclawHome(), "state", "openclaw.sqlite");
|
|
1666
|
+
}
|
|
1667
|
+
function readCronJobsByAgentId(agentId, sqlitePath = defaultOpenclawSqlitePath(), onError) {
|
|
1668
|
+
let db;
|
|
1669
|
+
try {
|
|
1670
|
+
db = new DatabaseSync(sqlitePath, { readOnly: true });
|
|
1671
|
+
return db.prepare("SELECT * FROM cron_jobs WHERE agent_id = ?").all(agentId);
|
|
1672
|
+
} catch (err) {
|
|
1673
|
+
onError?.(err);
|
|
1674
|
+
return [];
|
|
1675
|
+
} finally {
|
|
1676
|
+
db?.close();
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1663
1679
|
var GatewayWsClient = class {
|
|
1664
1680
|
ws = null;
|
|
1665
1681
|
options;
|
|
@@ -1965,8 +1981,29 @@ var GatewayWsClient = class {
|
|
|
1965
1981
|
isBuiltIn,
|
|
1966
1982
|
hasDirectUrl: Boolean(url)
|
|
1967
1983
|
});
|
|
1968
|
-
if (!action
|
|
1969
|
-
this.appendLogToFile("WARN", "Command", `Message dropped: missing action
|
|
1984
|
+
if (!action) {
|
|
1985
|
+
this.appendLogToFile("WARN", "Command", `Message dropped: missing action`, msg);
|
|
1986
|
+
return;
|
|
1987
|
+
}
|
|
1988
|
+
if (action === "GET_CRON_JOBS_BY_AGENT_ID") {
|
|
1989
|
+
const agentId = typeof msg.agent_id === "string" ? msg.agent_id : msg.agentId;
|
|
1990
|
+
if (!agentId) {
|
|
1991
|
+
this.reply(replyId, { success: false, message: "Missing agent_id parameter", action });
|
|
1992
|
+
return;
|
|
1993
|
+
}
|
|
1994
|
+
try {
|
|
1995
|
+
const data = readCronJobsByAgentId(agentId, defaultOpenclawSqlitePath(), (err) => {
|
|
1996
|
+
this.appendLogToFile("WARN", "Command", `GET_CRON_JOBS_BY_AGENT_ID sqlite lookup skipped`, err);
|
|
1997
|
+
});
|
|
1998
|
+
this.reply(replyId, { success: true, data, action });
|
|
1999
|
+
} catch (err) {
|
|
2000
|
+
this.appendLogToFile("ERROR", "Command", `GET_CRON_JOBS_BY_AGENT_ID threw`, err);
|
|
2001
|
+
this.reply(replyId, { success: false, message: err.message, action });
|
|
2002
|
+
}
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
2005
|
+
if (!userId) {
|
|
2006
|
+
this.appendLogToFile("WARN", "Command", `Message dropped: missing userId`, msg);
|
|
1970
2007
|
return;
|
|
1971
2008
|
}
|
|
1972
2009
|
const safeCode = code ? path7.basename(code) : void 0;
|
|
@@ -2088,6 +2125,12 @@ var GatewayWsClient = class {
|
|
|
2088
2125
|
setTimeout(async () => {
|
|
2089
2126
|
try {
|
|
2090
2127
|
const additionalTargetDirs = syncBuiltInTemplate ? [path7.join(openclawHome(), "workspace-xgjk-assistant-template", "skills")] : [];
|
|
2128
|
+
const userSkillDir = path7.join(openclawHome(), `workspace-assistant-${pureId}`, ".user", "skills", safeCode);
|
|
2129
|
+
try {
|
|
2130
|
+
await fs6.stat(userSkillDir);
|
|
2131
|
+
additionalTargetDirs.push(userSkillDir);
|
|
2132
|
+
} catch {
|
|
2133
|
+
}
|
|
2091
2134
|
const result = await this.options.updater.manualInstall({
|
|
2092
2135
|
code: safeCode,
|
|
2093
2136
|
url,
|
package/package.json
CHANGED
package/src/ws-client.test.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { describe, it } from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { DatabaseSync } from "node:sqlite";
|
|
3
7
|
import {
|
|
4
8
|
normalizeAssistantUserId,
|
|
5
9
|
parseAssistantWorkspaceAgentId,
|
|
10
|
+
readCronJobsByAgentId,
|
|
6
11
|
shouldSyncBuiltInTemplate,
|
|
7
12
|
} from "./ws-client.ts";
|
|
8
13
|
|
|
@@ -46,3 +51,78 @@ describe("built-in template update boundary", () => {
|
|
|
46
51
|
assert.equal(shouldSyncBuiltInTemplate("UNINSTALL_SKILL", true), false);
|
|
47
52
|
});
|
|
48
53
|
});
|
|
54
|
+
|
|
55
|
+
describe("cron job sqlite lookup", () => {
|
|
56
|
+
it("returns all cron_jobs rows for the requested agent_id", () => {
|
|
57
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-cron-jobs-"));
|
|
58
|
+
const dbPath = path.join(dir, "openclaw.sqlite");
|
|
59
|
+
const db = new DatabaseSync(dbPath);
|
|
60
|
+
try {
|
|
61
|
+
db.exec(`
|
|
62
|
+
CREATE TABLE cron_jobs (
|
|
63
|
+
id INTEGER PRIMARY KEY,
|
|
64
|
+
agent_id TEXT NOT NULL,
|
|
65
|
+
name TEXT NOT NULL,
|
|
66
|
+
cron TEXT NOT NULL
|
|
67
|
+
);
|
|
68
|
+
`);
|
|
69
|
+
db.prepare("INSERT INTO cron_jobs (agent_id, name, cron) VALUES (?, ?, ?)").run(
|
|
70
|
+
"assistant-1579723293989240833",
|
|
71
|
+
"morning",
|
|
72
|
+
"0 9 * * *"
|
|
73
|
+
);
|
|
74
|
+
db.prepare("INSERT INTO cron_jobs (agent_id, name, cron) VALUES (?, ?, ?)").run(
|
|
75
|
+
"assistant-1579723293989240833",
|
|
76
|
+
"evening",
|
|
77
|
+
"0 18 * * *"
|
|
78
|
+
);
|
|
79
|
+
db.prepare("INSERT INTO cron_jobs (agent_id, name, cron) VALUES (?, ?, ?)").run(
|
|
80
|
+
"assistant-000001",
|
|
81
|
+
"other",
|
|
82
|
+
"0 12 * * *"
|
|
83
|
+
);
|
|
84
|
+
} finally {
|
|
85
|
+
db.close();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const rows = readCronJobsByAgentId("assistant-1579723293989240833", dbPath);
|
|
89
|
+
|
|
90
|
+
assert.equal(rows.length, 2);
|
|
91
|
+
assert.deepEqual(
|
|
92
|
+
rows.map((row) => row.name),
|
|
93
|
+
["morning", "evening"]
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("returns an empty list when no cron_jobs row matches", () => {
|
|
98
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-cron-jobs-"));
|
|
99
|
+
const dbPath = path.join(dir, "openclaw.sqlite");
|
|
100
|
+
const db = new DatabaseSync(dbPath);
|
|
101
|
+
try {
|
|
102
|
+
db.exec("CREATE TABLE cron_jobs (id INTEGER PRIMARY KEY, agent_id TEXT NOT NULL);");
|
|
103
|
+
} finally {
|
|
104
|
+
db.close();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
assert.deepEqual(readCronJobsByAgentId("assistant-1579723293989240833", dbPath), []);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("returns an empty list when the sqlite file is not readable", () => {
|
|
111
|
+
const missingPath = path.join(os.tmpdir(), `missing-openclaw-${Date.now()}.sqlite`);
|
|
112
|
+
|
|
113
|
+
assert.deepEqual(readCronJobsByAgentId("assistant-1579723293989240833", missingPath), []);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("returns an empty list when cron_jobs table does not exist", () => {
|
|
117
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-cron-jobs-"));
|
|
118
|
+
const dbPath = path.join(dir, "openclaw.sqlite");
|
|
119
|
+
const db = new DatabaseSync(dbPath);
|
|
120
|
+
try {
|
|
121
|
+
db.exec("CREATE TABLE other_table (id INTEGER PRIMARY KEY, agent_id TEXT NOT NULL);");
|
|
122
|
+
} finally {
|
|
123
|
+
db.close();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
assert.deepEqual(readCronJobsByAgentId("assistant-1579723293989240833", dbPath), []);
|
|
127
|
+
});
|
|
128
|
+
});
|
package/src/ws-client.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import WebSocket from "ws";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import fs from "fs/promises";
|
|
4
|
+
import { DatabaseSync } from "node:sqlite";
|
|
4
5
|
import { SkillUpdater } from "./updater.ts";
|
|
5
6
|
import { openclawHome } from "./paths.ts";
|
|
6
7
|
import { readSkillVersion } from "./skill-version.ts";
|
|
@@ -33,6 +34,27 @@ export function shouldSyncBuiltInTemplate(action: string, isBuiltIn: unknown): b
|
|
|
33
34
|
return action === "UPDATE_SKILL" && isBuiltIn === true;
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
export function defaultOpenclawSqlitePath(): string {
|
|
38
|
+
return path.join(openclawHome(), "state", "openclaw.sqlite");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function readCronJobsByAgentId(
|
|
42
|
+
agentId: string,
|
|
43
|
+
sqlitePath = defaultOpenclawSqlitePath(),
|
|
44
|
+
onError?: (err: unknown) => void
|
|
45
|
+
): any[] {
|
|
46
|
+
let db: DatabaseSync | undefined;
|
|
47
|
+
try {
|
|
48
|
+
db = new DatabaseSync(sqlitePath, { readOnly: true });
|
|
49
|
+
return db.prepare("SELECT * FROM cron_jobs WHERE agent_id = ?").all(agentId);
|
|
50
|
+
} catch (err) {
|
|
51
|
+
onError?.(err);
|
|
52
|
+
return [];
|
|
53
|
+
} finally {
|
|
54
|
+
db?.close();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
36
58
|
export interface WsClientOptions {
|
|
37
59
|
serverUrl: string; // 例如: wss://api.aishuo.co/gateway/ws
|
|
38
60
|
authToken?: string; // 用于网关鉴权
|
|
@@ -396,8 +418,31 @@ export class GatewayWsClient {
|
|
|
396
418
|
hasDirectUrl: Boolean(url),
|
|
397
419
|
});
|
|
398
420
|
|
|
399
|
-
if (!action
|
|
400
|
-
this.appendLogToFile("WARN", "Command", `Message dropped: missing action
|
|
421
|
+
if (!action) {
|
|
422
|
+
this.appendLogToFile("WARN", "Command", `Message dropped: missing action`, msg);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
if (action === "GET_CRON_JOBS_BY_AGENT_ID") {
|
|
427
|
+
const agentId = typeof msg.agent_id === "string" ? msg.agent_id : msg.agentId;
|
|
428
|
+
if (!agentId) {
|
|
429
|
+
this.reply(replyId, { success: false, message: "Missing agent_id parameter", action });
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
try {
|
|
433
|
+
const data = readCronJobsByAgentId(agentId, defaultOpenclawSqlitePath(), (err) => {
|
|
434
|
+
this.appendLogToFile("WARN", "Command", `GET_CRON_JOBS_BY_AGENT_ID sqlite lookup skipped`, err);
|
|
435
|
+
});
|
|
436
|
+
this.reply(replyId, { success: true, data, action });
|
|
437
|
+
} catch (err: any) {
|
|
438
|
+
this.appendLogToFile("ERROR", "Command", `GET_CRON_JOBS_BY_AGENT_ID threw`, err);
|
|
439
|
+
this.reply(replyId, { success: false, message: err.message, action });
|
|
440
|
+
}
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (!userId) {
|
|
445
|
+
this.appendLogToFile("WARN", "Command", `Message dropped: missing userId`, msg);
|
|
401
446
|
return;
|
|
402
447
|
}
|
|
403
448
|
|
|
@@ -536,9 +581,16 @@ export class GatewayWsClient {
|
|
|
536
581
|
|
|
537
582
|
setTimeout(async () => {
|
|
538
583
|
try {
|
|
539
|
-
const additionalTargetDirs = syncBuiltInTemplate
|
|
584
|
+
const additionalTargetDirs: string[] = syncBuiltInTemplate
|
|
540
585
|
? [path.join(openclawHome(), "workspace-xgjk-assistant-template", "skills")]
|
|
541
586
|
: [];
|
|
587
|
+
|
|
588
|
+
// 同步更新用户的 expert skill 目录
|
|
589
|
+
const userSkillDir = path.join(openclawHome(), `workspace-assistant-${pureId}`, ".user", "skills", safeCode);
|
|
590
|
+
try {
|
|
591
|
+
await fs.stat(userSkillDir);
|
|
592
|
+
additionalTargetDirs.push(userSkillDir);
|
|
593
|
+
} catch {} // 目录不存在则跳过
|
|
542
594
|
const result = await this.options.updater.manualInstall({
|
|
543
595
|
code: safeCode,
|
|
544
596
|
url,
|