@vite-plugin-opencode-assistant/opencode 1.0.57 → 1.0.58

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.
@@ -0,0 +1,3 @@
1
+ import type { Hooks } from "@opencode-ai/plugin";
2
+ export declare const ServiceLogsPlugin: () => Promise<Hooks>;
3
+ export default ServiceLogsPlugin;
@@ -0,0 +1,212 @@
1
+ import { t as h } from "./tool.js";
2
+ import { c as v } from "./logger.js";
3
+ const o = {};
4
+ var y = Object.defineProperty, E = (s, e, t) => e in s ? y(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t, n = (s, e, t) => E(s, typeof e != "symbol" ? e + "" : e, t);
5
+ const a = v("FileLogWatcher");
6
+ class F {
7
+ constructor(e) {
8
+ n(this, "buffer", []), n(this, "maxSize"), n(this, "name"), n(this, "filePath"), n(this, "lastPosition", 0), n(this, "watcher", null), n(this, "enabled", !1);
9
+ var t;
10
+ this.name = e.name, this.filePath = e.filePath, this.maxSize = (t = e.maxBufferSize) != null ? t : 200, this.enabled = !0;
11
+ }
12
+ start(e) {
13
+ const t = this.resolvePath(e);
14
+ if (!o.existsSync(t)) {
15
+ a.debug(`Log file does not exist: ${t}`);
16
+ return;
17
+ }
18
+ const i = o.statSync(t);
19
+ this.lastPosition = i.size, this.watcher = o.watch(t, (r) => {
20
+ r === "change" && this.readNewLogs(t);
21
+ }), this.watcher.on("error", (r) => {
22
+ a.error(`Error watching file ${t}`, { error: r });
23
+ }), a.info(`Started watching log file: ${t}`);
24
+ }
25
+ stop() {
26
+ this.watcher && (this.watcher.close(), this.watcher = null, a.debug(`Stopped watching log file: ${this.filePath}`));
27
+ }
28
+ resolvePath(e) {
29
+ return o.isAbsolute(this.filePath) ? this.filePath : e ? o.resolve(e, this.filePath) : o.resolve(process.cwd(), this.filePath);
30
+ }
31
+ readNewLogs(e) {
32
+ try {
33
+ const t = o.statSync(e);
34
+ if (t.size <= this.lastPosition)
35
+ return;
36
+ const i = o.openSync(e, "r"), r = Buffer.alloc(t.size - this.lastPosition);
37
+ o.readSync(i, r, 0, r.length, this.lastPosition), o.closeSync(i), this.lastPosition = t.size;
38
+ const f = r.toString("utf-8").trim();
39
+ f && this.processLogContent(f);
40
+ } catch (t) {
41
+ a.error(`Error reading log file ${e}`, { error: t });
42
+ }
43
+ }
44
+ processLogContent(e) {
45
+ const t = e.split(`
46
+ `);
47
+ for (const i of t)
48
+ i.trim() && this.addEntry({
49
+ level: this.detectLogLevel(i),
50
+ message: i,
51
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
52
+ source: `file:${this.name}`
53
+ });
54
+ }
55
+ detectLogLevel(e) {
56
+ const t = e.toLowerCase();
57
+ return t.includes("error") || t.includes("err") || t.includes("fatal") ? "error" : t.includes("warn") || t.includes("warning") ? "warn" : "info";
58
+ }
59
+ addEntry(e) {
60
+ this.enabled && (this.buffer.length >= this.maxSize && this.buffer.shift(), this.buffer.push(e));
61
+ }
62
+ getLogs(e = {}) {
63
+ let t = [...this.buffer];
64
+ if (e.level) {
65
+ const i = Array.isArray(e.level) ? e.level : [e.level];
66
+ t = t.filter((r) => i.includes(r.level));
67
+ }
68
+ if (e.since) {
69
+ const i = new Date(e.since);
70
+ t = t.filter((r) => new Date(r.timestamp) >= i);
71
+ }
72
+ return e.limit && e.limit > 0 && (t = t.slice(-e.limit)), t;
73
+ }
74
+ clear() {
75
+ this.buffer = [];
76
+ }
77
+ size() {
78
+ return this.buffer.length;
79
+ }
80
+ setEnabled(e) {
81
+ this.enabled = e;
82
+ }
83
+ isEnabled() {
84
+ return this.enabled;
85
+ }
86
+ getName() {
87
+ return this.name;
88
+ }
89
+ getFilePath() {
90
+ return this.filePath;
91
+ }
92
+ }
93
+ class z {
94
+ constructor() {
95
+ n(this, "buffers", /* @__PURE__ */ new Map()), n(this, "projectRoot", null);
96
+ }
97
+ setProjectRoot(e) {
98
+ this.projectRoot = e;
99
+ }
100
+ addLogFile(e) {
101
+ var t;
102
+ if (this.buffers.has(e.name)) {
103
+ a.warn(`Log file "${e.name}" already exists, skipping`);
104
+ return;
105
+ }
106
+ const i = new F(e);
107
+ i.start((t = this.projectRoot) != null ? t : void 0), this.buffers.set(e.name, i), a.info(`Added log file watcher: ${e.name} -> ${e.filePath}`);
108
+ }
109
+ removeLogFile(e) {
110
+ const t = this.buffers.get(e);
111
+ t && (t.stop(), this.buffers.delete(e), a.info(`Removed log file watcher: ${e}`));
112
+ }
113
+ getBuffer(e) {
114
+ return this.buffers.get(e);
115
+ }
116
+ getAllBuffers() {
117
+ return this.buffers;
118
+ }
119
+ stopAll() {
120
+ for (const [e, t] of this.buffers)
121
+ t.stop(), a.debug(`Stopped log file watcher: ${e}`);
122
+ this.buffers.clear();
123
+ }
124
+ getLogFileNames() {
125
+ return Array.from(this.buffers.keys());
126
+ }
127
+ }
128
+ let d = null;
129
+ function N() {
130
+ return d || (d = new z()), d;
131
+ }
132
+ const l = v("ServiceLogsPlugin"), B = async () => {
133
+ l.debug("ServiceLogsPlugin loading...");
134
+ const s = process.env.OPENCODE_LOG_FILES_JSON;
135
+ if (l.debug("Log files JSON from env:", { logFilesJson: s ? "set" : "not set" }), !s)
136
+ return l.debug("OPENCODE_LOG_FILES_JSON is not set, service logs plugin will not register tools"), {};
137
+ let e;
138
+ try {
139
+ e = JSON.parse(s), l.debug("Parsed log files config", { count: e.length });
140
+ } catch (r) {
141
+ return l.error("Failed to parse OPENCODE_LOG_FILES_JSON", { error: r }), {};
142
+ }
143
+ if (!e || e.length === 0)
144
+ return l.debug("No log files configured, plugin will not register any tools"), {};
145
+ const t = N();
146
+ t.setProjectRoot(process.cwd());
147
+ for (const r of e)
148
+ t.addLogFile({
149
+ name: r.name,
150
+ filePath: r.path,
151
+ maxBufferSize: r.maxBufferSize,
152
+ watchExisting: r.watchExisting
153
+ }), l.debug(`Added log file watcher: ${r.name} -> ${r.path}`);
154
+ const i = {};
155
+ for (const r of e) {
156
+ const f = `get_${r.name}_logs`, L = `获取 ${r.name} 的日志。
157
+
158
+ **何时使用此工具**:
159
+ ${r.description}
160
+
161
+ **日志内容**:
162
+ - 来自日志文件 ${r.path} 的实时日志
163
+ - 最多保留 ${r.maxBufferSize ?? 200} 条日志`, S = h({
164
+ description: L,
165
+ args: {
166
+ level: h.schema.string().optional().describe(
167
+ "日志级别过滤:error(错误)、warn(警告)、info(信息)。多个用逗号分隔,如 'error,warn'"
168
+ ),
169
+ limit: h.schema.number().int().min(1).max(200).optional().default(50).describe("返回条数,默认 50,最大 200"),
170
+ since: h.schema.string().optional().describe("起始时间(ISO 格式),获取此时间之后的日志")
171
+ },
172
+ async execute(m, b) {
173
+ const { level: w, limit: p, since: P } = m;
174
+ l.debug(`${f} called`, {
175
+ args: m,
176
+ sessionID: b.sessionID,
177
+ directory: b.directory
178
+ });
179
+ const g = t.getBuffer(r.name);
180
+ if (!g)
181
+ return `日志文件 "${r.name}" 未找到。请检查配置。`;
182
+ const u = g.getLogs({
183
+ level: w ? w.split(",").map((c) => c.trim()) : void 0,
184
+ limit: p,
185
+ since: P
186
+ });
187
+ if (u.length === 0)
188
+ return `当前没有符合条件的日志(缓冲区共 ${g.size()} 条)。
189
+
190
+ 建议:
191
+ - 不指定参数获取所有日志
192
+ - 使用 level=error,warn 获取错误和警告`;
193
+ const $ = u.map((c) => {
194
+ const _ = new Date(c.timestamp).toLocaleTimeString(), O = c.level === "error" ? "❌" : c.level === "warn" ? "⚠️" : "ℹ️";
195
+ return `${_} ${O} ${c.message}`;
196
+ }).join(`
197
+ `);
198
+ return `${r.name} 日志(${u.length}/${g.size()} 条):
199
+
200
+ ${$}`;
201
+ }
202
+ });
203
+ i[f] = S, l.debug(`Registered tool: ${f}`);
204
+ }
205
+ return l.debug(`Plugin initialized with ${Object.keys(i).length} log tools`), {
206
+ tool: i
207
+ };
208
+ };
209
+ export {
210
+ B as ServiceLogsPlugin,
211
+ B as default
212
+ };
@@ -0,0 +1,124 @@
1
+ var __async = (__this, __arguments, generator) => {
2
+ return new Promise((resolve, reject) => {
3
+ var fulfilled = (value) => {
4
+ try {
5
+ step(generator.next(value));
6
+ } catch (e) {
7
+ reject(e);
8
+ }
9
+ };
10
+ var rejected = (value) => {
11
+ try {
12
+ step(generator.throw(value));
13
+ } catch (e) {
14
+ reject(e);
15
+ }
16
+ };
17
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
18
+ step((generator = generator.apply(__this, __arguments)).next());
19
+ });
20
+ };
21
+ import { tool } from "@opencode-ai/plugin";
22
+ import { createLogger, getServiceLogWatcher } from "@vite-plugin-opencode-assistant/shared";
23
+ const log = createLogger("ServiceLogsPlugin");
24
+ const ServiceLogsPlugin = () => __async(null, null, function* () {
25
+ var _a;
26
+ log.debug("ServiceLogsPlugin loading...");
27
+ const logFilesJson = process.env.OPENCODE_LOG_FILES_JSON;
28
+ log.debug("Log files JSON from env:", { logFilesJson: logFilesJson ? "set" : "not set" });
29
+ if (!logFilesJson) {
30
+ log.debug("OPENCODE_LOG_FILES_JSON is not set, service logs plugin will not register tools");
31
+ return {};
32
+ }
33
+ let logFiles;
34
+ try {
35
+ logFiles = JSON.parse(logFilesJson);
36
+ log.debug("Parsed log files config", { count: logFiles.length });
37
+ } catch (e) {
38
+ log.error("Failed to parse OPENCODE_LOG_FILES_JSON", { error: e });
39
+ return {};
40
+ }
41
+ if (!logFiles || logFiles.length === 0) {
42
+ log.debug("No log files configured, plugin will not register any tools");
43
+ return {};
44
+ }
45
+ const watcher = getServiceLogWatcher();
46
+ watcher.setProjectRoot(process.cwd());
47
+ for (const logFileConfig of logFiles) {
48
+ watcher.addLogFile({
49
+ name: logFileConfig.name,
50
+ filePath: logFileConfig.path,
51
+ maxBufferSize: logFileConfig.maxBufferSize,
52
+ watchExisting: logFileConfig.watchExisting
53
+ });
54
+ log.debug(`Added log file watcher: ${logFileConfig.name} -> ${logFileConfig.path}`);
55
+ }
56
+ const tools = {};
57
+ for (const logFileConfig of logFiles) {
58
+ let _b;
59
+ const toolName = `get_${logFileConfig.name}_logs`;
60
+ const description = `\u83B7\u53D6 ${logFileConfig.name} \u7684\u65E5\u5FD7\u3002
61
+
62
+ **\u4F55\u65F6\u4F7F\u7528\u6B64\u5DE5\u5177**\uFF1A
63
+ ${logFileConfig.description}
64
+
65
+ **\u65E5\u5FD7\u5185\u5BB9**\uFF1A
66
+ - \u6765\u81EA\u65E5\u5FD7\u6587\u4EF6 ${logFileConfig.path} \u7684\u5B9E\u65F6\u65E5\u5FD7
67
+ - \u6700\u591A\u4FDD\u7559 ${(_a = logFileConfig.maxBufferSize) != null ? _a : 200} \u6761\u65E5\u5FD7`;
68
+ const getLogsTool = tool({
69
+ description,
70
+ args: {
71
+ level: tool.schema.string().optional().describe(
72
+ "\u65E5\u5FD7\u7EA7\u522B\u8FC7\u6EE4\uFF1Aerror(\u9519\u8BEF)\u3001warn(\u8B66\u544A)\u3001info(\u4FE1\u606F)\u3002\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694\uFF0C\u5982 'error,warn'"
73
+ ),
74
+ limit: tool.schema.number().int().min(1).max(200).optional().default(50).describe("\u8FD4\u56DE\u6761\u6570\uFF0C\u9ED8\u8BA4 50\uFF0C\u6700\u5927 200"),
75
+ since: tool.schema.string().optional().describe("\u8D77\u59CB\u65F6\u95F4\uFF08ISO \u683C\u5F0F\uFF09\uFF0C\u83B7\u53D6\u6B64\u65F6\u95F4\u4E4B\u540E\u7684\u65E5\u5FD7")
76
+ },
77
+ execute(args, context) {
78
+ return __async(this, null, function* () {
79
+ const { level, limit, since } = args;
80
+ log.debug(`${toolName} called`, {
81
+ args,
82
+ sessionID: context.sessionID,
83
+ directory: context.directory
84
+ });
85
+ const buffer = watcher.getBuffer(logFileConfig.name);
86
+ if (!buffer) {
87
+ return `\u65E5\u5FD7\u6587\u4EF6 "${logFileConfig.name}" \u672A\u627E\u5230\u3002\u8BF7\u68C0\u67E5\u914D\u7F6E\u3002`;
88
+ }
89
+ const logs = buffer.getLogs({
90
+ level: level ? level.split(",").map((l) => l.trim()) : void 0,
91
+ limit,
92
+ since
93
+ });
94
+ if (logs.length === 0) {
95
+ return `\u5F53\u524D\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u65E5\u5FD7\uFF08\u7F13\u51B2\u533A\u5171 ${buffer.size()} \u6761\uFF09\u3002
96
+
97
+ \u5EFA\u8BAE\uFF1A
98
+ - \u4E0D\u6307\u5B9A\u53C2\u6570\u83B7\u53D6\u6240\u6709\u65E5\u5FD7
99
+ - \u4F7F\u7528 level=error,warn \u83B7\u53D6\u9519\u8BEF\u548C\u8B66\u544A`;
100
+ }
101
+ const formattedLogs = logs.map((entry) => {
102
+ const time = new Date(entry.timestamp).toLocaleTimeString();
103
+ const levelIcon = entry.level === "error" ? "\u274C" : entry.level === "warn" ? "\u26A0\uFE0F" : "\u2139\uFE0F";
104
+ return `${time} ${levelIcon} ${entry.message}`;
105
+ }).join("\n");
106
+ return `${logFileConfig.name} \u65E5\u5FD7\uFF08${logs.length}/${buffer.size()} \u6761\uFF09\uFF1A
107
+
108
+ ${formattedLogs}`;
109
+ });
110
+ }
111
+ });
112
+ tools[toolName] = getLogsTool;
113
+ log.debug(`Registered tool: ${toolName}`);
114
+ }
115
+ log.debug(`Plugin initialized with ${Object.keys(tools).length} log tools`);
116
+ return {
117
+ tool: tools
118
+ };
119
+ });
120
+ var service_logs_default = ServiceLogsPlugin;
121
+ export {
122
+ ServiceLogsPlugin,
123
+ service_logs_default as default
124
+ };