@prbe.ai/electron-sdk 0.1.6 → 0.1.7
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.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +213 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +213 -18
- package/dist/index.mjs.map +1 -1
- package/dist/{types-DHT-JxMT.d.mts → types-CwYRJCG0.d.mts} +11 -2
- package/dist/{types-DHT-JxMT.d.ts → types-CwYRJCG0.d.ts} +11 -2
- package/dist/types.d.mts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/agent.ts
|
|
2
|
-
import * as
|
|
3
|
-
import * as
|
|
4
|
-
import * as
|
|
2
|
+
import * as fs3 from "fs";
|
|
3
|
+
import * as path5 from "path";
|
|
4
|
+
import * as os2 from "os";
|
|
5
5
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
6
6
|
|
|
7
7
|
// src/models.ts
|
|
@@ -180,7 +180,7 @@ var PRBEAgentState = class extends EventEmitter {
|
|
|
180
180
|
this.emit("status" /* STATUS */);
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
|
-
completeInvestigation(report, summary) {
|
|
183
|
+
completeInvestigation(report, summary, ticketId) {
|
|
184
184
|
if (this.events.length > 0) {
|
|
185
185
|
this.events[this.events.length - 1].isCompleted = true;
|
|
186
186
|
}
|
|
@@ -190,6 +190,9 @@ var PRBEAgentState = class extends EventEmitter {
|
|
|
190
190
|
query: this.currentQuery,
|
|
191
191
|
report,
|
|
192
192
|
summary,
|
|
193
|
+
ticketId,
|
|
194
|
+
events: [...this.events],
|
|
195
|
+
resolvedInteractions: [...this.resolvedInteractions],
|
|
193
196
|
completedAt: /* @__PURE__ */ new Date()
|
|
194
197
|
});
|
|
195
198
|
this.report = report;
|
|
@@ -265,11 +268,12 @@ var PRBEAgentState = class extends EventEmitter {
|
|
|
265
268
|
}
|
|
266
269
|
}
|
|
267
270
|
// ---------- CR state mutations ----------
|
|
268
|
-
beginCR(id, query, slug) {
|
|
271
|
+
beginCR(id, query, slug, ticketId) {
|
|
269
272
|
const cr = {
|
|
270
273
|
id,
|
|
271
274
|
query,
|
|
272
275
|
slug,
|
|
276
|
+
ticketId,
|
|
273
277
|
events: [],
|
|
274
278
|
resolvedInteractions: [],
|
|
275
279
|
isRunning: true,
|
|
@@ -1499,20 +1503,196 @@ var BashExecuteTool = class {
|
|
|
1499
1503
|
}
|
|
1500
1504
|
};
|
|
1501
1505
|
|
|
1502
|
-
// src/
|
|
1503
|
-
|
|
1506
|
+
// src/history.ts
|
|
1507
|
+
import * as fs2 from "fs";
|
|
1508
|
+
import * as path4 from "path";
|
|
1509
|
+
import * as os from "os";
|
|
1510
|
+
import * as crypto from "crypto";
|
|
1511
|
+
var HKDF_SALT = Buffer.from("prbe-history-encryption-salt", "utf-8");
|
|
1512
|
+
var HKDF_INFO = Buffer.from("prbe-history-v1", "utf-8");
|
|
1513
|
+
function getAppDataDir() {
|
|
1504
1514
|
const appData = process.env["APPDATA"] || (process.platform === "darwin" ? path4.join(os.homedir(), "Library", "Application Support") : path4.join(os.homedir(), ".local", "share"));
|
|
1505
|
-
|
|
1515
|
+
return path4.join(appData, "prbe-agent");
|
|
1516
|
+
}
|
|
1517
|
+
function getHistoryDir() {
|
|
1518
|
+
const dir = path4.join(getAppDataDir(), "history" /* HISTORY_DIR */);
|
|
1506
1519
|
if (!fs2.existsSync(dir)) {
|
|
1507
1520
|
fs2.mkdirSync(dir, { recursive: true });
|
|
1508
1521
|
}
|
|
1509
|
-
return
|
|
1522
|
+
return dir;
|
|
1523
|
+
}
|
|
1524
|
+
function deriveKey(apiKey) {
|
|
1525
|
+
return Buffer.from(
|
|
1526
|
+
crypto.hkdfSync(
|
|
1527
|
+
"sha256",
|
|
1528
|
+
Buffer.from(apiKey, "utf-8"),
|
|
1529
|
+
HKDF_SALT,
|
|
1530
|
+
HKDF_INFO,
|
|
1531
|
+
32 /* KEY_LENGTH */
|
|
1532
|
+
)
|
|
1533
|
+
);
|
|
1534
|
+
}
|
|
1535
|
+
function encrypt(plaintext, key) {
|
|
1536
|
+
const iv = crypto.randomBytes(12 /* IV_LENGTH */);
|
|
1537
|
+
const cipher = crypto.createCipheriv(
|
|
1538
|
+
"aes-256-gcm" /* ALGORITHM */,
|
|
1539
|
+
key,
|
|
1540
|
+
iv,
|
|
1541
|
+
{ authTagLength: 16 /* AUTH_TAG_LENGTH */ }
|
|
1542
|
+
);
|
|
1543
|
+
const encrypted = Buffer.concat([cipher.update(plaintext, "utf-8"), cipher.final()]);
|
|
1544
|
+
const authTag = cipher.getAuthTag();
|
|
1545
|
+
return Buffer.concat([iv, authTag, encrypted]);
|
|
1546
|
+
}
|
|
1547
|
+
function decrypt(data, key) {
|
|
1548
|
+
const iv = data.subarray(0, 12 /* IV_LENGTH */);
|
|
1549
|
+
const authTag = data.subarray(
|
|
1550
|
+
12 /* IV_LENGTH */,
|
|
1551
|
+
12 /* IV_LENGTH */ + 16 /* AUTH_TAG_LENGTH */
|
|
1552
|
+
);
|
|
1553
|
+
const ciphertext = data.subarray(
|
|
1554
|
+
12 /* IV_LENGTH */ + 16 /* AUTH_TAG_LENGTH */
|
|
1555
|
+
);
|
|
1556
|
+
const decipher = crypto.createDecipheriv(
|
|
1557
|
+
"aes-256-gcm" /* ALGORITHM */,
|
|
1558
|
+
key,
|
|
1559
|
+
iv,
|
|
1560
|
+
{ authTagLength: 16 /* AUTH_TAG_LENGTH */ }
|
|
1561
|
+
);
|
|
1562
|
+
decipher.setAuthTag(authTag);
|
|
1563
|
+
return decipher.update(ciphertext) + decipher.final("utf-8");
|
|
1564
|
+
}
|
|
1565
|
+
var HistoryStore = class {
|
|
1566
|
+
key;
|
|
1567
|
+
constructor(apiKey) {
|
|
1568
|
+
this.key = deriveKey(apiKey);
|
|
1569
|
+
}
|
|
1570
|
+
load() {
|
|
1571
|
+
const investigations = [];
|
|
1572
|
+
const crs = [];
|
|
1573
|
+
try {
|
|
1574
|
+
const dir = getHistoryDir();
|
|
1575
|
+
let files;
|
|
1576
|
+
try {
|
|
1577
|
+
files = fs2.readdirSync(dir);
|
|
1578
|
+
} catch {
|
|
1579
|
+
return { investigations, crs };
|
|
1580
|
+
}
|
|
1581
|
+
for (const filename of files) {
|
|
1582
|
+
try {
|
|
1583
|
+
const filePath = path4.join(dir, filename);
|
|
1584
|
+
const raw = fs2.readFileSync(filePath);
|
|
1585
|
+
const json = decrypt(raw, this.key);
|
|
1586
|
+
if (filename.startsWith("inv-") && filename.endsWith(".json")) {
|
|
1587
|
+
const item = JSON.parse(json);
|
|
1588
|
+
investigations.push({
|
|
1589
|
+
...item,
|
|
1590
|
+
completedAt: new Date(item.completedAt)
|
|
1591
|
+
});
|
|
1592
|
+
} else if (filename.startsWith("cr-") && filename.endsWith(".json")) {
|
|
1593
|
+
const item = JSON.parse(json);
|
|
1594
|
+
crs.push({
|
|
1595
|
+
...item,
|
|
1596
|
+
startedAt: new Date(item.startedAt),
|
|
1597
|
+
resolvedInteractions: item.resolvedInteractions ?? []
|
|
1598
|
+
});
|
|
1599
|
+
}
|
|
1600
|
+
} catch {
|
|
1601
|
+
console.warn(`[PRBEAgent] Skipping unreadable history file: ${filename}`);
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
} catch {
|
|
1605
|
+
}
|
|
1606
|
+
investigations.sort(
|
|
1607
|
+
(a, b) => b.completedAt.getTime() - a.completedAt.getTime()
|
|
1608
|
+
);
|
|
1609
|
+
crs.sort((a, b) => b.startedAt.getTime() - a.startedAt.getTime());
|
|
1610
|
+
return { investigations, crs };
|
|
1611
|
+
}
|
|
1612
|
+
save(investigations, crs) {
|
|
1613
|
+
try {
|
|
1614
|
+
const dir = getHistoryDir();
|
|
1615
|
+
const desiredFiles = /* @__PURE__ */ new Set();
|
|
1616
|
+
for (const inv of investigations) {
|
|
1617
|
+
const filename = `inv-${inv.id}.json`;
|
|
1618
|
+
desiredFiles.add(filename);
|
|
1619
|
+
const data = {
|
|
1620
|
+
id: inv.id,
|
|
1621
|
+
query: inv.query,
|
|
1622
|
+
report: inv.report,
|
|
1623
|
+
summary: inv.summary,
|
|
1624
|
+
ticketId: inv.ticketId,
|
|
1625
|
+
events: inv.events,
|
|
1626
|
+
resolvedInteractions: inv.resolvedInteractions,
|
|
1627
|
+
completedAt: inv.completedAt.toISOString()
|
|
1628
|
+
};
|
|
1629
|
+
fs2.writeFileSync(
|
|
1630
|
+
path4.join(dir, filename),
|
|
1631
|
+
encrypt(JSON.stringify(data), this.key)
|
|
1632
|
+
);
|
|
1633
|
+
}
|
|
1634
|
+
for (const cr of crs) {
|
|
1635
|
+
const filename = `cr-${cr.id}.json`;
|
|
1636
|
+
desiredFiles.add(filename);
|
|
1637
|
+
const data = {
|
|
1638
|
+
id: cr.id,
|
|
1639
|
+
query: cr.query,
|
|
1640
|
+
slug: cr.slug,
|
|
1641
|
+
ticketId: cr.ticketId,
|
|
1642
|
+
events: cr.events,
|
|
1643
|
+
isRunning: cr.isRunning,
|
|
1644
|
+
isCompleted: cr.isCompleted,
|
|
1645
|
+
isFailed: cr.isFailed,
|
|
1646
|
+
report: cr.report,
|
|
1647
|
+
summary: cr.summary,
|
|
1648
|
+
errorMessage: cr.errorMessage,
|
|
1649
|
+
startedAt: cr.startedAt.toISOString(),
|
|
1650
|
+
pendingInteraction: cr.pendingInteraction,
|
|
1651
|
+
resolvedInteractions: cr.resolvedInteractions ?? []
|
|
1652
|
+
};
|
|
1653
|
+
fs2.writeFileSync(
|
|
1654
|
+
path4.join(dir, filename),
|
|
1655
|
+
encrypt(JSON.stringify(data), this.key)
|
|
1656
|
+
);
|
|
1657
|
+
}
|
|
1658
|
+
try {
|
|
1659
|
+
const existing = fs2.readdirSync(dir);
|
|
1660
|
+
for (const filename of existing) {
|
|
1661
|
+
if (!desiredFiles.has(filename)) {
|
|
1662
|
+
fs2.unlinkSync(path4.join(dir, filename));
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
} catch {
|
|
1666
|
+
}
|
|
1667
|
+
} catch {
|
|
1668
|
+
console.error("[PRBEAgent] Failed to save investigation history");
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
static clear() {
|
|
1672
|
+
try {
|
|
1673
|
+
const dir = path4.join(getAppDataDir(), "history" /* HISTORY_DIR */);
|
|
1674
|
+
if (fs2.existsSync(dir)) {
|
|
1675
|
+
fs2.rmSync(dir, { recursive: true, force: true });
|
|
1676
|
+
}
|
|
1677
|
+
} catch {
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
};
|
|
1681
|
+
|
|
1682
|
+
// src/agent.ts
|
|
1683
|
+
function getPersistencePath() {
|
|
1684
|
+
const appData = process.env["APPDATA"] || (process.platform === "darwin" ? path5.join(os2.homedir(), "Library", "Application Support") : path5.join(os2.homedir(), ".local", "share"));
|
|
1685
|
+
const dir = path5.join(appData, "prbe-agent");
|
|
1686
|
+
if (!fs3.existsSync(dir)) {
|
|
1687
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
1688
|
+
}
|
|
1689
|
+
return path5.join(dir, "agent-state.json");
|
|
1510
1690
|
}
|
|
1511
1691
|
function loadPersistedData() {
|
|
1512
1692
|
try {
|
|
1513
1693
|
const filePath = getPersistencePath();
|
|
1514
|
-
if (
|
|
1515
|
-
const raw =
|
|
1694
|
+
if (fs3.existsSync(filePath)) {
|
|
1695
|
+
const raw = fs3.readFileSync(filePath, "utf-8");
|
|
1516
1696
|
return JSON.parse(raw);
|
|
1517
1697
|
}
|
|
1518
1698
|
} catch {
|
|
@@ -1522,7 +1702,7 @@ function loadPersistedData() {
|
|
|
1522
1702
|
function savePersistedData(data) {
|
|
1523
1703
|
try {
|
|
1524
1704
|
const filePath = getPersistencePath();
|
|
1525
|
-
|
|
1705
|
+
fs3.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
1526
1706
|
} catch {
|
|
1527
1707
|
console.error("[PRBEAgent] Failed to save persisted data");
|
|
1528
1708
|
}
|
|
@@ -1542,6 +1722,7 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
1542
1722
|
fetchAbortController = null;
|
|
1543
1723
|
currentInvestigationSource = "user" /* USER */;
|
|
1544
1724
|
currentCRId = null;
|
|
1725
|
+
historyStore;
|
|
1545
1726
|
/** Files flagged during the current tool call — uploaded immediately after the tool returns. */
|
|
1546
1727
|
pendingFlaggedFiles = [];
|
|
1547
1728
|
// ---------- Persistence ----------
|
|
@@ -1603,6 +1784,10 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
1603
1784
|
this.state = new PRBEAgentState();
|
|
1604
1785
|
this.logCapture = new PRBELogCapture(this.config.maxLogEntries);
|
|
1605
1786
|
this.persistedData = loadPersistedData();
|
|
1787
|
+
this.historyStore = new HistoryStore(this.config.apiKey);
|
|
1788
|
+
const history = this.historyStore.load();
|
|
1789
|
+
this.state.completedInvestigations = history.investigations;
|
|
1790
|
+
this.state.completedCRs = history.crs;
|
|
1606
1791
|
const roots = this.config.autoApprovedDirs;
|
|
1607
1792
|
const requester = this.interactionHandler ? this : void 0;
|
|
1608
1793
|
const grantedPaths = this.grantedPaths;
|
|
@@ -1753,7 +1938,8 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
1753
1938
|
this.state.appendEvent("Thinking", status.text);
|
|
1754
1939
|
break;
|
|
1755
1940
|
case "completed" /* COMPLETED */:
|
|
1756
|
-
this.state.completeInvestigation(status.report, status.userSummary);
|
|
1941
|
+
this.state.completeInvestigation(status.report, status.userSummary, status.ticketId);
|
|
1942
|
+
this.historyStore.save(this.state.completedInvestigations, this.state.completedCRs);
|
|
1757
1943
|
break;
|
|
1758
1944
|
case "error" /* ERROR */:
|
|
1759
1945
|
this.state.failInvestigation(status.message);
|
|
@@ -1895,6 +2081,7 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
1895
2081
|
this.stopPolling();
|
|
1896
2082
|
this.persistedData = {};
|
|
1897
2083
|
savePersistedData(this.persistedData);
|
|
2084
|
+
HistoryStore.clear();
|
|
1898
2085
|
this.state.resetInvestigation();
|
|
1899
2086
|
this.state.completedInvestigations = [];
|
|
1900
2087
|
this.state.activeCRs.clear();
|
|
@@ -1909,9 +2096,10 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
1909
2096
|
static clearPersistedData() {
|
|
1910
2097
|
try {
|
|
1911
2098
|
const filePath = getPersistencePath();
|
|
1912
|
-
if (
|
|
1913
|
-
|
|
2099
|
+
if (fs3.existsSync(filePath)) {
|
|
2100
|
+
fs3.unlinkSync(filePath);
|
|
1914
2101
|
}
|
|
2102
|
+
HistoryStore.clear();
|
|
1915
2103
|
} catch {
|
|
1916
2104
|
}
|
|
1917
2105
|
}
|
|
@@ -1920,7 +2108,7 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
1920
2108
|
const crID = cr.id;
|
|
1921
2109
|
this.currentInvestigationSource = "context_request" /* CONTEXT_REQUEST */;
|
|
1922
2110
|
this.currentCRId = crID;
|
|
1923
|
-
this.state.beginCR(crID, cr.query, cr.slug ?? void 0);
|
|
2111
|
+
this.state.beginCR(crID, cr.query, cr.slug ?? void 0, ticketId);
|
|
1924
2112
|
const emitter = (status) => {
|
|
1925
2113
|
switch (status.type) {
|
|
1926
2114
|
case "started" /* STARTED */:
|
|
@@ -1939,9 +2127,11 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
1939
2127
|
break;
|
|
1940
2128
|
case "completed" /* COMPLETED */:
|
|
1941
2129
|
this.state.completeCR(crID, status.report, status.userSummary);
|
|
2130
|
+
this.historyStore.save(this.state.completedInvestigations, this.state.completedCRs);
|
|
1942
2131
|
break;
|
|
1943
2132
|
case "error" /* ERROR */:
|
|
1944
2133
|
this.state.failCR(crID, status.message);
|
|
2134
|
+
this.historyStore.save(this.state.completedInvestigations, this.state.completedCRs);
|
|
1945
2135
|
break;
|
|
1946
2136
|
}
|
|
1947
2137
|
};
|
|
@@ -2080,7 +2270,7 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2080
2270
|
const uploadPrefix = this.extractUploadPrefix(uploadBaseUrl);
|
|
2081
2271
|
const uploadedRefs = [];
|
|
2082
2272
|
for (const file of this.pendingFlaggedFiles) {
|
|
2083
|
-
const filename =
|
|
2273
|
+
const filename = path5.basename(file.originalPath);
|
|
2084
2274
|
const safeName = encodeURIComponent(filename);
|
|
2085
2275
|
const storagePath = `${uploadPrefix}/${safeName}`;
|
|
2086
2276
|
uploadedRefs.push({
|
|
@@ -2136,7 +2326,8 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2136
2326
|
emit({
|
|
2137
2327
|
type: "completed" /* COMPLETED */,
|
|
2138
2328
|
report,
|
|
2139
|
-
userSummary
|
|
2329
|
+
userSummary,
|
|
2330
|
+
ticketId: ticketId2
|
|
2140
2331
|
});
|
|
2141
2332
|
ws.close(1e3, "Complete");
|
|
2142
2333
|
finish({ report, userSummary, ticketId: ticketId2 });
|
|
@@ -2319,6 +2510,7 @@ function serializeCR(cr) {
|
|
|
2319
2510
|
id: cr.id,
|
|
2320
2511
|
query: cr.query,
|
|
2321
2512
|
slug: cr.slug,
|
|
2513
|
+
ticketId: cr.ticketId,
|
|
2322
2514
|
events: cr.events,
|
|
2323
2515
|
isRunning: cr.isRunning,
|
|
2324
2516
|
isCompleted: cr.isCompleted,
|
|
@@ -2346,6 +2538,9 @@ function serializePRBEState(state) {
|
|
|
2346
2538
|
query: inv.query,
|
|
2347
2539
|
report: inv.report,
|
|
2348
2540
|
summary: inv.summary,
|
|
2541
|
+
ticketId: inv.ticketId,
|
|
2542
|
+
events: inv.events,
|
|
2543
|
+
resolvedInteractions: inv.resolvedInteractions,
|
|
2349
2544
|
completedAt: inv.completedAt.toISOString()
|
|
2350
2545
|
})),
|
|
2351
2546
|
activeCRs: Array.from(state.activeCRs.values()).map(serializeCR),
|