@openqa/cli 1.0.6 → 1.0.8
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/agent/index.js +161 -109
- package/dist/agent/index.js.map +1 -1
- package/dist/cli/index.js +163 -111
- package/dist/database/index.js +156 -108
- package/dist/database/index.js.map +1 -1
- package/package.json +2 -3
package/dist/cli/index.js
CHANGED
|
@@ -12,123 +12,171 @@ import { Tracer } from "@orka-js/observability";
|
|
|
12
12
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
13
13
|
|
|
14
14
|
// database/index.ts
|
|
15
|
-
import
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
15
|
+
import { Low } from "lowdb";
|
|
16
|
+
import { JSONFile } from "lowdb/node";
|
|
17
|
+
import { dirname } from "path";
|
|
18
18
|
import { fileURLToPath } from "url";
|
|
19
19
|
import { mkdirSync } from "fs";
|
|
20
20
|
var __filename = fileURLToPath(import.meta.url);
|
|
21
21
|
var __dirname = dirname(__filename);
|
|
22
22
|
var OpenQADatabase = class {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const dir = dirname(dbPath);
|
|
26
|
-
mkdirSync(dir, { recursive: true });
|
|
27
|
-
this.db = new Database(dbPath);
|
|
23
|
+
constructor(dbPath = "./data/openqa.json") {
|
|
24
|
+
this.dbPath = dbPath;
|
|
28
25
|
this.initialize();
|
|
29
26
|
}
|
|
27
|
+
db = null;
|
|
30
28
|
initialize() {
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
getSession(id) {
|
|
54
|
-
return this.db.prepare("SELECT * FROM test_sessions WHERE id = ?").get(id);
|
|
29
|
+
const dir = dirname(this.dbPath);
|
|
30
|
+
mkdirSync(dir, { recursive: true });
|
|
31
|
+
const adapter = new JSONFile(this.dbPath);
|
|
32
|
+
this.db = new Low(adapter, {
|
|
33
|
+
config: {},
|
|
34
|
+
test_sessions: [],
|
|
35
|
+
actions: [],
|
|
36
|
+
bugs: [],
|
|
37
|
+
kanban_tickets: []
|
|
38
|
+
});
|
|
39
|
+
this.db.read();
|
|
40
|
+
if (!this.db.data) {
|
|
41
|
+
this.db.data = {
|
|
42
|
+
config: {},
|
|
43
|
+
test_sessions: [],
|
|
44
|
+
actions: [],
|
|
45
|
+
bugs: [],
|
|
46
|
+
kanban_tickets: []
|
|
47
|
+
};
|
|
48
|
+
this.db.write();
|
|
49
|
+
}
|
|
55
50
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
51
|
+
async ensureInitialized() {
|
|
52
|
+
if (!this.db) {
|
|
53
|
+
this.initialize();
|
|
54
|
+
}
|
|
55
|
+
await this.db.read();
|
|
60
56
|
}
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
async getConfig(key) {
|
|
58
|
+
await this.ensureInitialized();
|
|
59
|
+
return this.db.data.config[key] || null;
|
|
63
60
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
this.db.
|
|
67
|
-
|
|
68
|
-
action.session_id,
|
|
69
|
-
action.type,
|
|
70
|
-
action.description,
|
|
71
|
-
action.input || null,
|
|
72
|
-
action.output || null,
|
|
73
|
-
action.screenshot_path || null
|
|
74
|
-
);
|
|
75
|
-
return this.db.prepare("SELECT * FROM actions WHERE id = ?").get(id);
|
|
61
|
+
async setConfig(key, value) {
|
|
62
|
+
await this.ensureInitialized();
|
|
63
|
+
this.db.data.config[key] = value;
|
|
64
|
+
await this.db.write();
|
|
76
65
|
}
|
|
77
|
-
|
|
78
|
-
|
|
66
|
+
async getAllConfig() {
|
|
67
|
+
await this.ensureInitialized();
|
|
68
|
+
return this.db.data.config;
|
|
79
69
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
70
|
+
async createSession(id, metadata) {
|
|
71
|
+
await this.ensureInitialized();
|
|
72
|
+
const session = {
|
|
83
73
|
id,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
);
|
|
92
|
-
return
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
74
|
+
started_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
75
|
+
status: "running",
|
|
76
|
+
total_actions: 0,
|
|
77
|
+
bugs_found: 0,
|
|
78
|
+
metadata: metadata ? JSON.stringify(metadata) : void 0
|
|
79
|
+
};
|
|
80
|
+
this.db.data.test_sessions.push(session);
|
|
81
|
+
await this.db.write();
|
|
82
|
+
return session;
|
|
83
|
+
}
|
|
84
|
+
async getSession(id) {
|
|
85
|
+
await this.ensureInitialized();
|
|
86
|
+
return this.db.data.test_sessions.find((s) => s.id === id) || null;
|
|
87
|
+
}
|
|
88
|
+
async updateSession(id, updates) {
|
|
89
|
+
await this.ensureInitialized();
|
|
90
|
+
const index = this.db.data.test_sessions.findIndex((s) => s.id === id);
|
|
91
|
+
if (index !== -1) {
|
|
92
|
+
this.db.data.test_sessions[index] = { ...this.db.data.test_sessions[index], ...updates };
|
|
93
|
+
await this.db.write();
|
|
94
|
+
}
|
|
101
95
|
}
|
|
102
|
-
|
|
103
|
-
|
|
96
|
+
async getRecentSessions(limit = 10) {
|
|
97
|
+
await this.ensureInitialized();
|
|
98
|
+
return this.db.data.test_sessions.sort((a, b) => new Date(b.started_at).getTime() - new Date(a.started_at).getTime()).slice(0, limit);
|
|
104
99
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
id,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
100
|
+
async createAction(action) {
|
|
101
|
+
await this.ensureInitialized();
|
|
102
|
+
const newAction = {
|
|
103
|
+
id: `action_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
104
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
105
|
+
...action
|
|
106
|
+
};
|
|
107
|
+
this.db.data.actions.push(newAction);
|
|
108
|
+
await this.db.write();
|
|
109
|
+
return newAction;
|
|
110
|
+
}
|
|
111
|
+
async getSessionActions(sessionId) {
|
|
112
|
+
await this.ensureInitialized();
|
|
113
|
+
return this.db.data.actions.filter((a) => a.session_id === sessionId).sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
114
|
+
}
|
|
115
|
+
async createBug(bug) {
|
|
116
|
+
await this.ensureInitialized();
|
|
117
|
+
const newBug = {
|
|
118
|
+
id: `bug_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
119
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
120
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
121
|
+
...bug
|
|
122
|
+
};
|
|
123
|
+
this.db.data.bugs.push(newBug);
|
|
124
|
+
await this.db.write();
|
|
125
|
+
return newBug;
|
|
126
|
+
}
|
|
127
|
+
async updateBug(id, updates) {
|
|
128
|
+
await this.ensureInitialized();
|
|
129
|
+
const index = this.db.data.bugs.findIndex((b) => b.id === id);
|
|
130
|
+
if (index !== -1) {
|
|
131
|
+
this.db.data.bugs[index] = {
|
|
132
|
+
...this.db.data.bugs[index],
|
|
133
|
+
...updates,
|
|
134
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
135
|
+
};
|
|
136
|
+
await this.db.write();
|
|
137
|
+
}
|
|
118
138
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
139
|
+
async getAllBugs() {
|
|
140
|
+
await this.ensureInitialized();
|
|
141
|
+
return this.db.data.bugs.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
142
|
+
}
|
|
143
|
+
async getBugsByStatus(status) {
|
|
144
|
+
await this.ensureInitialized();
|
|
145
|
+
return this.db.data.bugs.filter((b) => b.status === status).sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
146
|
+
}
|
|
147
|
+
async createKanbanTicket(ticket) {
|
|
148
|
+
await this.ensureInitialized();
|
|
149
|
+
const newTicket = {
|
|
150
|
+
id: `ticket_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
151
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
152
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
153
|
+
...ticket
|
|
154
|
+
};
|
|
155
|
+
this.db.data.kanban_tickets.push(newTicket);
|
|
156
|
+
await this.db.write();
|
|
157
|
+
return newTicket;
|
|
158
|
+
}
|
|
159
|
+
async updateKanbanTicket(id, updates) {
|
|
160
|
+
await this.ensureInitialized();
|
|
161
|
+
const index = this.db.data.kanban_tickets.findIndex((t) => t.id === id);
|
|
162
|
+
if (index !== -1) {
|
|
163
|
+
this.db.data.kanban_tickets[index] = {
|
|
164
|
+
...this.db.data.kanban_tickets[index],
|
|
165
|
+
...updates,
|
|
166
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
167
|
+
};
|
|
168
|
+
await this.db.write();
|
|
169
|
+
}
|
|
123
170
|
}
|
|
124
|
-
getKanbanTickets() {
|
|
125
|
-
|
|
171
|
+
async getKanbanTickets() {
|
|
172
|
+
await this.ensureInitialized();
|
|
173
|
+
return this.db.data.kanban_tickets.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
126
174
|
}
|
|
127
|
-
getKanbanTicketsByColumn(column) {
|
|
128
|
-
|
|
175
|
+
async getKanbanTicketsByColumn(column) {
|
|
176
|
+
await this.ensureInitialized();
|
|
177
|
+
return this.db.data.kanban_tickets.filter((t) => t.column === column).sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
129
178
|
}
|
|
130
|
-
close() {
|
|
131
|
-
this.db.close();
|
|
179
|
+
async close() {
|
|
132
180
|
}
|
|
133
181
|
};
|
|
134
182
|
|
|
@@ -179,8 +227,8 @@ var ConfigManager = class {
|
|
|
179
227
|
}
|
|
180
228
|
};
|
|
181
229
|
}
|
|
182
|
-
get(key) {
|
|
183
|
-
const dbValue = this.db.getConfig(key);
|
|
230
|
+
async get(key) {
|
|
231
|
+
const dbValue = await this.db.getConfig(key);
|
|
184
232
|
if (dbValue) return dbValue;
|
|
185
233
|
const keys = key.split(".");
|
|
186
234
|
let value = this.envConfig;
|
|
@@ -189,11 +237,11 @@ var ConfigManager = class {
|
|
|
189
237
|
}
|
|
190
238
|
return value?.toString() || null;
|
|
191
239
|
}
|
|
192
|
-
set(key, value) {
|
|
193
|
-
this.db.setConfig(key, value);
|
|
240
|
+
async set(key, value) {
|
|
241
|
+
await this.db.setConfig(key, value);
|
|
194
242
|
}
|
|
195
|
-
getAll() {
|
|
196
|
-
const dbConfig = this.db.getAllConfig();
|
|
243
|
+
async getAll() {
|
|
244
|
+
const dbConfig = await this.db.getAllConfig();
|
|
197
245
|
const merged = { ...this.envConfig };
|
|
198
246
|
for (const [key, value] of Object.entries(dbConfig)) {
|
|
199
247
|
const keys = key.split(".");
|
|
@@ -206,8 +254,12 @@ var ConfigManager = class {
|
|
|
206
254
|
}
|
|
207
255
|
return merged;
|
|
208
256
|
}
|
|
209
|
-
getConfig() {
|
|
210
|
-
return this.getAll();
|
|
257
|
+
async getConfig() {
|
|
258
|
+
return await this.getAll();
|
|
259
|
+
}
|
|
260
|
+
// Synchronous version that only uses env vars (no DB)
|
|
261
|
+
getConfigSync() {
|
|
262
|
+
return this.envConfig;
|
|
211
263
|
}
|
|
212
264
|
};
|
|
213
265
|
|
|
@@ -1325,11 +1377,11 @@ var OpenQAAgent = class extends EventEmitter3 {
|
|
|
1325
1377
|
constructor(configPath) {
|
|
1326
1378
|
super();
|
|
1327
1379
|
this.config = new ConfigManager(configPath);
|
|
1328
|
-
this.db = new OpenQADatabase(
|
|
1380
|
+
this.db = new OpenQADatabase("./data/openqa.json");
|
|
1329
1381
|
this.skillManager = new SkillManager(this.db);
|
|
1330
1382
|
}
|
|
1331
1383
|
createLLMAdapter() {
|
|
1332
|
-
const cfg = this.config.
|
|
1384
|
+
const cfg = this.config.getConfigSync();
|
|
1333
1385
|
switch (cfg.llm.provider) {
|
|
1334
1386
|
case "anthropic":
|
|
1335
1387
|
return new AnthropicAdapter2({
|
|
@@ -1345,9 +1397,9 @@ var OpenQAAgent = class extends EventEmitter3 {
|
|
|
1345
1397
|
}
|
|
1346
1398
|
}
|
|
1347
1399
|
async initialize(triggerType = "manual", triggerData) {
|
|
1348
|
-
const cfg = this.config.
|
|
1400
|
+
const cfg = this.config.getConfigSync();
|
|
1349
1401
|
this.sessionId = `session_${Date.now()}`;
|
|
1350
|
-
this.db.createSession(this.sessionId, {
|
|
1402
|
+
await this.db.createSession(this.sessionId, {
|
|
1351
1403
|
config: cfg,
|
|
1352
1404
|
started_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1353
1405
|
trigger_type: triggerType,
|
|
@@ -1583,7 +1635,7 @@ Always provide clear, actionable information with steps to reproduce. Think step
|
|
|
1583
1635
|
|
|
1584
1636
|
// cli/index.ts
|
|
1585
1637
|
import { spawn } from "child_process";
|
|
1586
|
-
import { writeFileSync, readFileSync as readFileSync2, existsSync, unlinkSync } from "fs";
|
|
1638
|
+
import { writeFileSync as writeFileSync2, readFileSync as readFileSync2, existsSync, unlinkSync } from "fs";
|
|
1587
1639
|
import { join as join3 } from "path";
|
|
1588
1640
|
import chalk from "chalk";
|
|
1589
1641
|
import ora from "ora";
|
|
@@ -1611,7 +1663,7 @@ program.command("start").description("Start the OpenQA agent and web UI").option
|
|
|
1611
1663
|
stdio: "ignore"
|
|
1612
1664
|
});
|
|
1613
1665
|
child.unref();
|
|
1614
|
-
|
|
1666
|
+
writeFileSync2(PID_FILE, child.pid.toString());
|
|
1615
1667
|
spinner.succeed(chalk.green("OpenQA started in daemon mode"));
|
|
1616
1668
|
console.log(chalk.cyan(`PID: ${child.pid}`));
|
|
1617
1669
|
} else {
|
package/dist/database/index.js
CHANGED
|
@@ -1,121 +1,169 @@
|
|
|
1
1
|
// database/index.ts
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { Low } from "lowdb";
|
|
3
|
+
import { JSONFile } from "lowdb/node";
|
|
4
|
+
import { dirname } from "path";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
import { mkdirSync } from "fs";
|
|
7
7
|
var __filename = fileURLToPath(import.meta.url);
|
|
8
8
|
var __dirname = dirname(__filename);
|
|
9
9
|
var OpenQADatabase = class {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const dir = dirname(dbPath);
|
|
13
|
-
mkdirSync(dir, { recursive: true });
|
|
14
|
-
this.db = new Database(dbPath);
|
|
10
|
+
constructor(dbPath = "./data/openqa.json") {
|
|
11
|
+
this.dbPath = dbPath;
|
|
15
12
|
this.initialize();
|
|
16
13
|
}
|
|
14
|
+
db = null;
|
|
17
15
|
initialize() {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
this.db.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return this.db.prepare("SELECT * FROM actions WHERE id = ?").get(id);
|
|
63
|
-
}
|
|
64
|
-
getSessionActions(sessionId) {
|
|
65
|
-
return this.db.prepare("SELECT * FROM actions WHERE session_id = ? ORDER BY timestamp DESC").all(sessionId);
|
|
66
|
-
}
|
|
67
|
-
createBug(bug) {
|
|
68
|
-
const id = `bug_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
69
|
-
this.db.prepare("INSERT INTO bugs (id, session_id, title, description, severity, status, github_issue_url, screenshot_path) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(
|
|
70
|
-
id,
|
|
71
|
-
bug.session_id,
|
|
72
|
-
bug.title,
|
|
73
|
-
bug.description,
|
|
74
|
-
bug.severity,
|
|
75
|
-
bug.status,
|
|
76
|
-
bug.github_issue_url || null,
|
|
77
|
-
bug.screenshot_path || null
|
|
78
|
-
);
|
|
79
|
-
return this.db.prepare("SELECT * FROM bugs WHERE id = ?").get(id);
|
|
80
|
-
}
|
|
81
|
-
updateBug(id, updates) {
|
|
82
|
-
const fields = Object.keys(updates).map((k) => `${k} = ?`).join(", ");
|
|
83
|
-
const values = [...Object.values(updates), id];
|
|
84
|
-
this.db.prepare(`UPDATE bugs SET ${fields}, updated_at = CURRENT_TIMESTAMP WHERE id = ?`).run(...values);
|
|
85
|
-
}
|
|
86
|
-
getAllBugs() {
|
|
87
|
-
return this.db.prepare("SELECT * FROM bugs ORDER BY created_at DESC").all();
|
|
88
|
-
}
|
|
89
|
-
getBugsByStatus(status) {
|
|
90
|
-
return this.db.prepare("SELECT * FROM bugs WHERE status = ? ORDER BY created_at DESC").all(status);
|
|
91
|
-
}
|
|
92
|
-
createKanbanTicket(ticket) {
|
|
93
|
-
const id = `ticket_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
94
|
-
this.db.prepare("INSERT INTO kanban_tickets (id, bug_id, title, description, priority, column, tags, screenshot_url) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(
|
|
16
|
+
const dir = dirname(this.dbPath);
|
|
17
|
+
mkdirSync(dir, { recursive: true });
|
|
18
|
+
const adapter = new JSONFile(this.dbPath);
|
|
19
|
+
this.db = new Low(adapter, {
|
|
20
|
+
config: {},
|
|
21
|
+
test_sessions: [],
|
|
22
|
+
actions: [],
|
|
23
|
+
bugs: [],
|
|
24
|
+
kanban_tickets: []
|
|
25
|
+
});
|
|
26
|
+
this.db.read();
|
|
27
|
+
if (!this.db.data) {
|
|
28
|
+
this.db.data = {
|
|
29
|
+
config: {},
|
|
30
|
+
test_sessions: [],
|
|
31
|
+
actions: [],
|
|
32
|
+
bugs: [],
|
|
33
|
+
kanban_tickets: []
|
|
34
|
+
};
|
|
35
|
+
this.db.write();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async ensureInitialized() {
|
|
39
|
+
if (!this.db) {
|
|
40
|
+
this.initialize();
|
|
41
|
+
}
|
|
42
|
+
await this.db.read();
|
|
43
|
+
}
|
|
44
|
+
async getConfig(key) {
|
|
45
|
+
await this.ensureInitialized();
|
|
46
|
+
return this.db.data.config[key] || null;
|
|
47
|
+
}
|
|
48
|
+
async setConfig(key, value) {
|
|
49
|
+
await this.ensureInitialized();
|
|
50
|
+
this.db.data.config[key] = value;
|
|
51
|
+
await this.db.write();
|
|
52
|
+
}
|
|
53
|
+
async getAllConfig() {
|
|
54
|
+
await this.ensureInitialized();
|
|
55
|
+
return this.db.data.config;
|
|
56
|
+
}
|
|
57
|
+
async createSession(id, metadata) {
|
|
58
|
+
await this.ensureInitialized();
|
|
59
|
+
const session = {
|
|
95
60
|
id,
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
);
|
|
104
|
-
return
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
61
|
+
started_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
62
|
+
status: "running",
|
|
63
|
+
total_actions: 0,
|
|
64
|
+
bugs_found: 0,
|
|
65
|
+
metadata: metadata ? JSON.stringify(metadata) : void 0
|
|
66
|
+
};
|
|
67
|
+
this.db.data.test_sessions.push(session);
|
|
68
|
+
await this.db.write();
|
|
69
|
+
return session;
|
|
70
|
+
}
|
|
71
|
+
async getSession(id) {
|
|
72
|
+
await this.ensureInitialized();
|
|
73
|
+
return this.db.data.test_sessions.find((s) => s.id === id) || null;
|
|
74
|
+
}
|
|
75
|
+
async updateSession(id, updates) {
|
|
76
|
+
await this.ensureInitialized();
|
|
77
|
+
const index = this.db.data.test_sessions.findIndex((s) => s.id === id);
|
|
78
|
+
if (index !== -1) {
|
|
79
|
+
this.db.data.test_sessions[index] = { ...this.db.data.test_sessions[index], ...updates };
|
|
80
|
+
await this.db.write();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async getRecentSessions(limit = 10) {
|
|
84
|
+
await this.ensureInitialized();
|
|
85
|
+
return this.db.data.test_sessions.sort((a, b) => new Date(b.started_at).getTime() - new Date(a.started_at).getTime()).slice(0, limit);
|
|
86
|
+
}
|
|
87
|
+
async createAction(action) {
|
|
88
|
+
await this.ensureInitialized();
|
|
89
|
+
const newAction = {
|
|
90
|
+
id: `action_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
91
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
92
|
+
...action
|
|
93
|
+
};
|
|
94
|
+
this.db.data.actions.push(newAction);
|
|
95
|
+
await this.db.write();
|
|
96
|
+
return newAction;
|
|
97
|
+
}
|
|
98
|
+
async getSessionActions(sessionId) {
|
|
99
|
+
await this.ensureInitialized();
|
|
100
|
+
return this.db.data.actions.filter((a) => a.session_id === sessionId).sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
101
|
+
}
|
|
102
|
+
async createBug(bug) {
|
|
103
|
+
await this.ensureInitialized();
|
|
104
|
+
const newBug = {
|
|
105
|
+
id: `bug_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
106
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
107
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
108
|
+
...bug
|
|
109
|
+
};
|
|
110
|
+
this.db.data.bugs.push(newBug);
|
|
111
|
+
await this.db.write();
|
|
112
|
+
return newBug;
|
|
113
|
+
}
|
|
114
|
+
async updateBug(id, updates) {
|
|
115
|
+
await this.ensureInitialized();
|
|
116
|
+
const index = this.db.data.bugs.findIndex((b) => b.id === id);
|
|
117
|
+
if (index !== -1) {
|
|
118
|
+
this.db.data.bugs[index] = {
|
|
119
|
+
...this.db.data.bugs[index],
|
|
120
|
+
...updates,
|
|
121
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
122
|
+
};
|
|
123
|
+
await this.db.write();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async getAllBugs() {
|
|
127
|
+
await this.ensureInitialized();
|
|
128
|
+
return this.db.data.bugs.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
129
|
+
}
|
|
130
|
+
async getBugsByStatus(status) {
|
|
131
|
+
await this.ensureInitialized();
|
|
132
|
+
return this.db.data.bugs.filter((b) => b.status === status).sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
133
|
+
}
|
|
134
|
+
async createKanbanTicket(ticket) {
|
|
135
|
+
await this.ensureInitialized();
|
|
136
|
+
const newTicket = {
|
|
137
|
+
id: `ticket_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
138
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
139
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
140
|
+
...ticket
|
|
141
|
+
};
|
|
142
|
+
this.db.data.kanban_tickets.push(newTicket);
|
|
143
|
+
await this.db.write();
|
|
144
|
+
return newTicket;
|
|
145
|
+
}
|
|
146
|
+
async updateKanbanTicket(id, updates) {
|
|
147
|
+
await this.ensureInitialized();
|
|
148
|
+
const index = this.db.data.kanban_tickets.findIndex((t) => t.id === id);
|
|
149
|
+
if (index !== -1) {
|
|
150
|
+
this.db.data.kanban_tickets[index] = {
|
|
151
|
+
...this.db.data.kanban_tickets[index],
|
|
152
|
+
...updates,
|
|
153
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
154
|
+
};
|
|
155
|
+
await this.db.write();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async getKanbanTickets() {
|
|
159
|
+
await this.ensureInitialized();
|
|
160
|
+
return this.db.data.kanban_tickets.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
161
|
+
}
|
|
162
|
+
async getKanbanTicketsByColumn(column) {
|
|
163
|
+
await this.ensureInitialized();
|
|
164
|
+
return this.db.data.kanban_tickets.filter((t) => t.column === column).sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
165
|
+
}
|
|
166
|
+
async close() {
|
|
119
167
|
}
|
|
120
168
|
};
|
|
121
169
|
export {
|