@prbe.ai/electron-sdk 0.1.9 → 0.1.12

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.mjs CHANGED
@@ -40,6 +40,7 @@ var ToolName = /* @__PURE__ */ ((ToolName2) => {
40
40
  ToolName2["CLIENT_FLAG_APP_LOGS"] = "client_flag_app_logs";
41
41
  ToolName2["CLIENT_ASK_USER"] = "client_ask_user";
42
42
  ToolName2["CLIENT_BASH_EXECUTE"] = "client_bash_execute";
43
+ ToolName2["CLIENT_MESSAGE_USER"] = "client_message_user";
43
44
  return ToolName2;
44
45
  })(ToolName || {});
45
46
  var PRBEAgentConfigKey = /* @__PURE__ */ ((PRBEAgentConfigKey3) => {
@@ -104,6 +105,7 @@ var PRBEStateEvent = /* @__PURE__ */ ((PRBEStateEvent2) => {
104
105
  PRBEStateEvent2["TICKET_INFO"] = "ticket-info";
105
106
  PRBEStateEvent2["INTERACTION_REQUESTED"] = "interaction-requested";
106
107
  PRBEStateEvent2["INTERACTION_RESOLVED"] = "interaction-resolved";
108
+ PRBEStateEvent2["AGENT_MESSAGE"] = "agent-message";
107
109
  return PRBEStateEvent2;
108
110
  })(PRBEStateEvent || {});
109
111
  var PRBEAgentState = class extends EventEmitter {
@@ -116,6 +118,7 @@ var PRBEAgentState = class extends EventEmitter {
116
118
  investigationError;
117
119
  pendingInteraction;
118
120
  resolvedInteractions = [];
121
+ agentMessage;
119
122
  // Completed user investigations (history)
120
123
  completedInvestigations = [];
121
124
  // Background context requests
@@ -143,6 +146,7 @@ var PRBEAgentState = class extends EventEmitter {
143
146
  this.summary = "";
144
147
  this.currentQuery = query;
145
148
  this.investigationError = void 0;
149
+ this.agentMessage = void 0;
146
150
  this.emit("status" /* STATUS */);
147
151
  }
148
152
  resetInvestigation() {
@@ -154,6 +158,7 @@ var PRBEAgentState = class extends EventEmitter {
154
158
  this.currentQuery = "";
155
159
  this.investigationError = void 0;
156
160
  this.pendingInteraction = void 0;
161
+ this.agentMessage = void 0;
157
162
  this.emit("status" /* STATUS */);
158
163
  }
159
164
  appendEvent(label, detail, completed = false) {
@@ -260,6 +265,18 @@ var PRBEAgentState = class extends EventEmitter {
260
265
  this.emit("interaction-resolved" /* INTERACTION_RESOLVED */);
261
266
  this.emit("status" /* STATUS */);
262
267
  }
268
+ setAgentMessage(message) {
269
+ this.agentMessage = message;
270
+ this.emit("agent-message" /* AGENT_MESSAGE */, { message });
271
+ this.emit("status" /* STATUS */);
272
+ }
273
+ setCRAgentMessage(crID, message) {
274
+ const cr = this.activeCRs.get(crID);
275
+ if (!cr) return;
276
+ cr.agentMessage = message;
277
+ this.emit("agent-message" /* AGENT_MESSAGE */, { message });
278
+ this.emit("status" /* STATUS */);
279
+ }
263
280
  toggleExpansion(eventId) {
264
281
  const event = this.events.find((e) => e.id === eventId);
265
282
  if (event) {
@@ -629,7 +646,8 @@ var SearchContentTool = class {
629
646
  { name: "pattern", type: "STRING" /* STRING */, description: "Regex pattern", required: true },
630
647
  { name: "path", type: "STRING" /* STRING */, description: "File or directory to search", required: true },
631
648
  { name: "context_lines", type: "INTEGER" /* INTEGER */, description: "Context lines (default 2)", required: false },
632
- { name: "max_results", type: "INTEGER" /* INTEGER */, description: "Max results (default 50)", required: false }
649
+ { name: "max_results", type: "INTEGER" /* INTEGER */, description: "Max results (default 50)", required: false },
650
+ { name: "case_sensitive", type: "BOOLEAN" /* BOOLEAN */, description: "Case-sensitive search (default false)", required: false }
633
651
  ]
634
652
  };
635
653
  }
@@ -642,9 +660,10 @@ var SearchContentTool = class {
642
660
  if (!resolved) return `Error: ${resolveErr}`;
643
661
  const contextLines = typeof args["context_lines"] === "number" ? args["context_lines"] : 2;
644
662
  const maxResults = typeof args["max_results"] === "number" ? args["max_results"] : 50;
663
+ const caseSensitive = args["case_sensitive"] === true;
645
664
  let regex;
646
665
  try {
647
- regex = new RegExp(pattern);
666
+ regex = new RegExp(pattern, caseSensitive ? "" : "i");
648
667
  } catch {
649
668
  return `Error: invalid regex pattern '${pattern}'`;
650
669
  }
@@ -732,7 +751,8 @@ var FindFilesTool = class {
732
751
  parameters: [
733
752
  { name: "pattern", type: "STRING" /* STRING */, description: "Glob pattern", required: true },
734
753
  { name: "path", type: "STRING" /* STRING */, description: "Directory to search", required: true },
735
- { name: "max_results", type: "INTEGER" /* INTEGER */, description: "Max results (default 50)", required: false }
754
+ { name: "max_results", type: "INTEGER" /* INTEGER */, description: "Max results (default 50)", required: false },
755
+ { name: "case_sensitive", type: "BOOLEAN" /* BOOLEAN */, description: "Case-sensitive matching (default false)", required: false }
736
756
  ]
737
757
  };
738
758
  }
@@ -744,8 +764,9 @@ var FindFilesTool = class {
744
764
  const [resolved, resolveErr] = await resolvePath(pathStr, this.autoApprovedDirs, this.requester, this.grantedPaths);
745
765
  if (!resolved) return `Error: ${resolveErr}`;
746
766
  const maxResults = typeof args["max_results"] === "number" ? args["max_results"] : 50;
767
+ const caseSensitive = args["case_sensitive"] === true;
747
768
  const matches = [];
748
- this.walkAndMatch(resolved, pattern, matches);
769
+ this.walkAndMatch(resolved, pattern, matches, caseSensitive);
749
770
  matches.sort((a, b) => b.modified.getTime() - a.modified.getTime());
750
771
  const limited = matches.slice(0, maxResults);
751
772
  if (limited.length === 0) {
@@ -762,7 +783,7 @@ var FindFilesTool = class {
762
783
  }
763
784
  return result;
764
785
  }
765
- walkAndMatch(dirPath, pattern, matches) {
786
+ walkAndMatch(dirPath, pattern, matches, caseSensitive) {
766
787
  let entries;
767
788
  try {
768
789
  entries = fs.readdirSync(dirPath, { withFileTypes: true });
@@ -773,9 +794,9 @@ var FindFilesTool = class {
773
794
  if (entry.name.startsWith(".")) continue;
774
795
  const fullPath = path2.join(dirPath, entry.name);
775
796
  if (entry.isDirectory()) {
776
- this.walkAndMatch(fullPath, pattern, matches);
797
+ this.walkAndMatch(fullPath, pattern, matches, caseSensitive);
777
798
  } else if (entry.isFile()) {
778
- if (this.globMatch(entry.name, pattern)) {
799
+ if (this.globMatch(entry.name, pattern, caseSensitive)) {
779
800
  try {
780
801
  const stat = fs.statSync(fullPath);
781
802
  matches.push({
@@ -793,7 +814,7 @@ var FindFilesTool = class {
793
814
  * Simple glob matching: supports *, ?, and character classes [...].
794
815
  * Converts glob to regex and tests against the filename.
795
816
  */
796
- globMatch(filename, pattern) {
817
+ globMatch(filename, pattern, caseSensitive) {
797
818
  let regexStr = "^";
798
819
  for (let i = 0; i < pattern.length; i++) {
799
820
  const c = pattern[i];
@@ -831,7 +852,7 @@ var FindFilesTool = class {
831
852
  }
832
853
  regexStr += "$";
833
854
  try {
834
- return new RegExp(regexStr).test(filename);
855
+ return new RegExp(regexStr, caseSensitive ? "" : "i").test(filename);
835
856
  } catch {
836
857
  return false;
837
858
  }
@@ -1290,70 +1311,136 @@ var AskUserTool = class {
1290
1311
  import { exec } from "child_process";
1291
1312
  import { randomUUID as randomUUID4 } from "crypto";
1292
1313
  import * as path3 from "path";
1293
- var IS_WINDOWS = process.platform === "win32";
1314
+
1315
+ // src/tools/safe-commands.ts
1294
1316
  var UNIX_SAFE_COMMANDS = /* @__PURE__ */ new Set([
1317
+ // Filesystem (read-only)
1295
1318
  "ls",
1296
1319
  "cat",
1297
1320
  "head",
1298
1321
  "tail",
1299
- "grep",
1300
- "rg",
1301
1322
  "find",
1302
- "which",
1303
- "whoami",
1304
- "pwd",
1305
- "echo",
1306
- "printf",
1307
- "wc",
1308
- "sort",
1309
- "uniq",
1310
- "diff",
1311
1323
  "file",
1312
1324
  "stat",
1313
1325
  "du",
1314
1326
  "df",
1327
+ "wc",
1328
+ "sort",
1329
+ "uniq",
1330
+ "diff",
1331
+ "tree",
1332
+ // Search
1333
+ "grep",
1334
+ "rg",
1335
+ "which",
1336
+ // Text
1337
+ "echo",
1338
+ "printf",
1339
+ // Identity / environment
1340
+ "whoami",
1341
+ "pwd",
1342
+ "id",
1343
+ "hostname",
1315
1344
  "uname",
1316
1345
  "env",
1317
1346
  "printenv",
1347
+ "locale",
1348
+ // System info (read-only reporters)
1318
1349
  "date",
1319
- "id",
1320
- "hostname",
1350
+ "uptime",
1351
+ "free",
1321
1352
  "ps",
1322
1353
  "top",
1323
- "uptime",
1324
- "free"
1354
+ // macOS-specific (read-only only)
1355
+ "sw_vers",
1356
+ // macOS version
1357
+ "system_profiler",
1358
+ // hardware/software info
1359
+ "mdls",
1360
+ // Spotlight metadata for a file
1361
+ "mdfind",
1362
+ // Spotlight search
1363
+ "lsof",
1364
+ // list open files
1365
+ "ioreg",
1366
+ // I/O registry (hardware tree)
1367
+ "log",
1368
+ // macOS unified log (show, stream — read-only)
1369
+ // Linux-specific (read-only reporters)
1370
+ "lsb_release",
1371
+ // distro info
1372
+ "lscpu",
1373
+ // CPU info
1374
+ "lsblk",
1375
+ // block devices
1376
+ "lspci",
1377
+ // PCI devices
1378
+ "lsusb",
1379
+ // USB devices
1380
+ "lsmem",
1381
+ // memory ranges
1382
+ "dmidecode",
1383
+ // BIOS/hardware info
1384
+ "ss",
1385
+ // socket statistics
1386
+ "journalctl"
1387
+ // systemd logs (read-only)
1325
1388
  ]);
1326
1389
  var WINDOWS_SAFE_COMMANDS = /* @__PURE__ */ new Set([
1390
+ // CMD — filesystem (read-only)
1327
1391
  "dir",
1328
1392
  "type",
1393
+ "tree",
1394
+ "more",
1329
1395
  "findstr",
1330
1396
  "where",
1397
+ // CMD — system info (read-only reporters)
1398
+ "systeminfo",
1399
+ "hostname",
1400
+ "ver",
1401
+ "vol",
1402
+ "date",
1403
+ "set",
1404
+ "path",
1405
+ "chcp",
1331
1406
  "whoami",
1332
1407
  "echo",
1333
1408
  "sort",
1334
1409
  "fc",
1335
- "hostname",
1336
- "date",
1337
- "systeminfo",
1410
+ // CMD — processes
1338
1411
  "tasklist",
1339
- "set",
1340
- "ver",
1341
- "vol",
1342
- "tree",
1343
- // PowerShell cmdlets (when shell is PowerShell)
1412
+ "driverquery",
1413
+ // CMD — network (read-only)
1414
+ "netstat",
1415
+ // CMD — policy (read-only)
1416
+ "gpresult",
1417
+ // PowerShell — Get-* cmdlets (strictly read-only by convention)
1344
1418
  "get-childitem",
1345
1419
  "get-content",
1420
+ "get-item",
1421
+ "test-path",
1422
+ "resolve-path",
1423
+ "get-itemproperty",
1346
1424
  "select-string",
1347
- "get-process",
1348
- "get-date",
1425
+ "measure-object",
1349
1426
  "get-host",
1350
1427
  "get-computerinfo",
1428
+ "get-date",
1351
1429
  "get-volume",
1352
- "test-path",
1353
- "resolve-path",
1354
- "measure-object"
1430
+ "get-disk",
1431
+ "get-partition",
1432
+ "get-process",
1433
+ "get-service",
1434
+ "get-netadapter",
1435
+ "get-nettcpconnection",
1436
+ "get-netipaddress",
1437
+ "get-netroute",
1438
+ "get-hotfix",
1439
+ "get-eventlog",
1440
+ "get-winevent",
1441
+ "get-wmiobject",
1442
+ "get-ciminstance"
1355
1443
  ]);
1356
- var SAFE_COMMANDS = IS_WINDOWS ? WINDOWS_SAFE_COMMANDS : UNIX_SAFE_COMMANDS;
1357
1444
  var SAFE_COMMAND_PREFIXES = /* @__PURE__ */ new Set([
1358
1445
  "git status",
1359
1446
  "git log",
@@ -1365,6 +1452,11 @@ var SAFE_COMMAND_PREFIXES = /* @__PURE__ */ new Set([
1365
1452
  "npm list",
1366
1453
  "npm ls"
1367
1454
  ]);
1455
+ var IS_WINDOWS = process.platform === "win32";
1456
+ var SAFE_COMMANDS = IS_WINDOWS ? WINDOWS_SAFE_COMMANDS : UNIX_SAFE_COMMANDS;
1457
+
1458
+ // src/tools/bash.ts
1459
+ var IS_WINDOWS2 = process.platform === "win32";
1368
1460
  var MAX_OUTPUT_BYTES = 100 * 1024;
1369
1461
  var DEFAULT_TIMEOUT_MS = 3e4;
1370
1462
  var MAX_TIMEOUT_MS = 12e4;
@@ -1442,7 +1534,7 @@ var BashExecuteTool = class {
1442
1534
  maxBuffer: MAX_OUTPUT_BYTES,
1443
1535
  env: process.env,
1444
1536
  // On Windows, use PowerShell for more consistent behavior
1445
- ...IS_WINDOWS ? { shell: "powershell.exe" } : {}
1537
+ ...IS_WINDOWS2 ? { shell: "powershell.exe" } : {}
1446
1538
  },
1447
1539
  (error, stdout, stderr) => {
1448
1540
  let output = "";
@@ -1479,9 +1571,9 @@ var BashExecuteTool = class {
1479
1571
  return true;
1480
1572
  }
1481
1573
  }
1482
- const firstCommand = IS_WINDOWS ? trimmed.split(/[|;]/, 1)[0].trim() : trimmed.split(/[|;&]/, 1)[0].trim();
1574
+ const firstCommand = IS_WINDOWS2 ? trimmed.split(/[|;]/, 1)[0].trim() : trimmed.split(/[|;&]/, 1)[0].trim();
1483
1575
  const baseCommand = firstCommand.split(/\s+/, 1)[0];
1484
- const commandName = IS_WINDOWS ? baseCommand.toLowerCase() : path3.basename(baseCommand);
1576
+ const commandName = IS_WINDOWS2 ? baseCommand.toLowerCase() : path3.basename(baseCommand);
1485
1577
  if (SAFE_COMMANDS.has(commandName)) {
1486
1578
  return this.areAllPipeSegmentsSafe(trimmed);
1487
1579
  }
@@ -1491,7 +1583,7 @@ var BashExecuteTool = class {
1491
1583
  * For piped commands, check that every segment uses a safe command.
1492
1584
  */
1493
1585
  areAllPipeSegmentsSafe(command) {
1494
- if (IS_WINDOWS) {
1586
+ if (IS_WINDOWS2) {
1495
1587
  if (/;/.test(command) && command.split("|").length <= 1) return false;
1496
1588
  } else {
1497
1589
  if (/[;&]|&&|\|\|/.test(command)) return false;
@@ -1499,7 +1591,7 @@ var BashExecuteTool = class {
1499
1591
  const segments = command.split("|").map((s) => s.trim());
1500
1592
  for (const segment of segments) {
1501
1593
  const baseCommand = segment.split(/\s+/, 1)[0];
1502
- const commandName = IS_WINDOWS ? baseCommand.toLowerCase() : path3.basename(baseCommand);
1594
+ const commandName = IS_WINDOWS2 ? baseCommand.toLowerCase() : path3.basename(baseCommand);
1503
1595
  if (!SAFE_COMMANDS.has(commandName)) {
1504
1596
  return false;
1505
1597
  }
@@ -1817,6 +1909,22 @@ var PRBEAgent = class _PRBEAgent {
1817
1909
  this.registry.register(new AskUserTool(requester));
1818
1910
  this.registry.register(new BashExecuteTool(requester, roots, grantedPaths));
1819
1911
  }
1912
+ this.registry.register(
1913
+ new PRBEClosureTool(
1914
+ "client_message_user",
1915
+ "Send a message to the user.",
1916
+ [{ name: "message", type: "STRING" /* STRING */, description: "Message for the user", required: true }],
1917
+ async (args) => {
1918
+ const message = args["message"] ?? "";
1919
+ if (this.currentInvestigationSource === "context_request" /* CONTEXT_REQUEST */ && this.currentCRId) {
1920
+ this.state.setCRAgentMessage(this.currentCRId, message);
1921
+ } else {
1922
+ this.state.setAgentMessage(message);
1923
+ }
1924
+ return "Message delivered.";
1925
+ }
1926
+ )
1927
+ );
1820
1928
  if (this.config.captureConsole) {
1821
1929
  this.logCapture.startCapturing();
1822
1930
  }
@@ -2204,7 +2312,10 @@ var PRBEAgent = class _PRBEAgent {
2204
2312
  }));
2205
2313
  const startMetadata = {
2206
2314
  agent_id: this.agentID,
2207
- custom_tools: toolDeclarations
2315
+ custom_tools: toolDeclarations,
2316
+ platform: os2.platform(),
2317
+ os_version: os2.release(),
2318
+ arch: os2.arch()
2208
2319
  };
2209
2320
  if (contextRequestID) {
2210
2321
  startMetadata["context_request_id"] = contextRequestID;
@@ -2543,6 +2654,7 @@ function serializeCR(cr) {
2543
2654
  report: cr.report,
2544
2655
  summary: cr.summary,
2545
2656
  errorMessage: cr.errorMessage,
2657
+ agentMessage: cr.agentMessage,
2546
2658
  startedAt: cr.startedAt.toISOString(),
2547
2659
  pendingInteraction: cr.pendingInteraction,
2548
2660
  resolvedInteractions: cr.resolvedInteractions ?? []
@@ -2558,6 +2670,7 @@ function serializePRBEState(state) {
2558
2670
  investigationError: state.investigationError,
2559
2671
  pendingInteraction: state.pendingInteraction,
2560
2672
  resolvedInteractions: state.resolvedInteractions,
2673
+ agentMessage: state.agentMessage,
2561
2674
  completedInvestigations: state.completedInvestigations.map((inv) => ({
2562
2675
  id: inv.id,
2563
2676
  query: inv.query,