@projectservan8n/cnapse 0.8.1 → 0.8.2

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 CHANGED
@@ -586,10 +586,10 @@ async function captureScreenFallback() {
586
586
  const { exec: exec5 } = await import("child_process");
587
587
  const { promisify: promisify5 } = await import("util");
588
588
  const { tmpdir } = await import("os");
589
- const { join: join3 } = await import("path");
589
+ const { join: join4 } = await import("path");
590
590
  const { readFile: readFile2, unlink } = await import("fs/promises");
591
591
  const execAsync5 = promisify5(exec5);
592
- const tempFile = join3(tmpdir(), `cnapse-screen-${Date.now()}.png`);
592
+ const tempFile = join4(tmpdir(), `cnapse-screen-${Date.now()}.png`);
593
593
  try {
594
594
  const platform = process.platform;
595
595
  if (platform === "win32") {
@@ -902,29 +902,29 @@ import { promisify as promisify4 } from "util";
902
902
  // src/tools/filesystem.ts
903
903
  import { promises as fs } from "fs";
904
904
  import { join, dirname } from "path";
905
- async function readFile(path2) {
905
+ async function readFile(path3) {
906
906
  try {
907
- const content = await fs.readFile(path2, "utf-8");
907
+ const content = await fs.readFile(path3, "utf-8");
908
908
  return ok(content);
909
909
  } catch (error) {
910
910
  return err(`Failed to read file: ${error.message}`);
911
911
  }
912
912
  }
913
- async function writeFile(path2, content) {
913
+ async function writeFile(path3, content) {
914
914
  try {
915
- const dir = dirname(path2);
915
+ const dir = dirname(path3);
916
916
  await fs.mkdir(dir, { recursive: true });
917
- await fs.writeFile(path2, content, "utf-8");
918
- return ok(`Written ${content.length} bytes to ${path2}`);
917
+ await fs.writeFile(path3, content, "utf-8");
918
+ return ok(`Written ${content.length} bytes to ${path3}`);
919
919
  } catch (error) {
920
920
  return err(`Failed to write file: ${error.message}`);
921
921
  }
922
922
  }
923
- async function listDir(path2, recursive = false) {
923
+ async function listDir(path3, recursive = false) {
924
924
  try {
925
- const stat = await fs.stat(path2);
925
+ const stat = await fs.stat(path3);
926
926
  if (!stat.isDirectory()) {
927
- return err(`Not a directory: ${path2}`);
927
+ return err(`Not a directory: ${path3}`);
928
928
  }
929
929
  const entries = [];
930
930
  async function walkDir(dir, prefix) {
@@ -941,7 +941,7 @@ async function listDir(path2, recursive = false) {
941
941
  }
942
942
  }
943
943
  }
944
- await walkDir(path2, "");
944
+ await walkDir(path3, "");
945
945
  entries.sort();
946
946
  return ok(entries.join("\n"));
947
947
  } catch (error) {
@@ -1460,7 +1460,9 @@ ${stderr}`
1460
1460
 
1461
1461
  // src/services/browser.ts
1462
1462
  import { chromium } from "playwright";
1463
- var browser = null;
1463
+ import * as path from "path";
1464
+ import * as os2 from "os";
1465
+ import * as fs2 from "fs";
1464
1466
  var context = null;
1465
1467
  var activePage = null;
1466
1468
  var defaultConfig = {
@@ -1468,23 +1470,69 @@ var defaultConfig = {
1468
1470
  // Show browser so user can see what's happening
1469
1471
  slowMo: 50,
1470
1472
  // Slight delay for visibility
1471
- viewport: { width: 1280, height: 800 }
1473
+ viewport: { width: 1280, height: 800 },
1474
+ useSystemBrowser: true
1475
+ // Default to using system Chrome
1472
1476
  };
1477
+ function findSystemBrowser() {
1478
+ const possiblePaths = [
1479
+ // Chrome paths
1480
+ path.join(process.env["PROGRAMFILES"] || "", "Google", "Chrome", "Application", "chrome.exe"),
1481
+ path.join(process.env["PROGRAMFILES(X86)"] || "", "Google", "Chrome", "Application", "chrome.exe"),
1482
+ path.join(process.env["LOCALAPPDATA"] || "", "Google", "Chrome", "Application", "chrome.exe"),
1483
+ // Edge paths (fallback)
1484
+ path.join(process.env["PROGRAMFILES"] || "", "Microsoft", "Edge", "Application", "msedge.exe"),
1485
+ path.join(process.env["PROGRAMFILES(X86)"] || "", "Microsoft", "Edge", "Application", "msedge.exe")
1486
+ ];
1487
+ for (const browserPath of possiblePaths) {
1488
+ if (fs2.existsSync(browserPath)) {
1489
+ return browserPath;
1490
+ }
1491
+ }
1492
+ return null;
1493
+ }
1494
+ function getChromeUserDataDir() {
1495
+ const cnapseProfile = path.join(os2.homedir(), ".cnapse", "chrome-profile");
1496
+ if (!fs2.existsSync(cnapseProfile)) {
1497
+ fs2.mkdirSync(cnapseProfile, { recursive: true });
1498
+ }
1499
+ return cnapseProfile;
1500
+ }
1473
1501
  async function initBrowser(config = {}) {
1474
1502
  const cfg = { ...defaultConfig, ...config };
1475
- if (!browser) {
1476
- browser = await chromium.launch({
1477
- headless: cfg.headless,
1478
- slowMo: cfg.slowMo
1479
- });
1480
- }
1481
1503
  if (!context) {
1482
- context = await browser.newContext({
1483
- viewport: cfg.viewport,
1484
- userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
1485
- });
1504
+ const browserPath = cfg.useSystemBrowser ? findSystemBrowser() : null;
1505
+ const userDataDir = getChromeUserDataDir();
1506
+ if (browserPath && cfg.useSystemBrowser) {
1507
+ context = await chromium.launchPersistentContext(userDataDir, {
1508
+ headless: cfg.headless,
1509
+ slowMo: cfg.slowMo,
1510
+ viewport: cfg.viewport,
1511
+ executablePath: browserPath,
1512
+ channel: void 0,
1513
+ // Don't use channel when specifying executablePath
1514
+ args: [
1515
+ "--disable-blink-features=AutomationControlled",
1516
+ // Less bot detection
1517
+ "--no-first-run",
1518
+ "--no-default-browser-check"
1519
+ ]
1520
+ });
1521
+ } else {
1522
+ context = await chromium.launchPersistentContext(userDataDir, {
1523
+ headless: cfg.headless,
1524
+ slowMo: cfg.slowMo,
1525
+ viewport: cfg.viewport,
1526
+ args: [
1527
+ "--disable-blink-features=AutomationControlled"
1528
+ ]
1529
+ });
1530
+ }
1486
1531
  }
1487
- if (!activePage) {
1532
+ const pages = context.pages();
1533
+ if (pages.length > 0) {
1534
+ activePage = pages[0];
1535
+ } else {
1488
1536
  activePage = await context.newPage();
1489
1537
  }
1490
1538
  return activePage;
@@ -1776,14 +1824,14 @@ async function research(topic, maxSources = 3) {
1776
1824
  }
1777
1825
 
1778
1826
  // src/lib/tasks.ts
1779
- import * as fs2 from "fs";
1780
- import * as path from "path";
1781
- import * as os2 from "os";
1782
- var TASK_MEMORY_FILE = path.join(os2.homedir(), ".cnapse", "task-memory.json");
1827
+ import * as fs3 from "fs";
1828
+ import * as path2 from "path";
1829
+ import * as os3 from "os";
1830
+ var TASK_MEMORY_FILE = path2.join(os3.homedir(), ".cnapse", "task-memory.json");
1783
1831
  function loadTaskMemory() {
1784
1832
  try {
1785
- if (fs2.existsSync(TASK_MEMORY_FILE)) {
1786
- const data = fs2.readFileSync(TASK_MEMORY_FILE, "utf-8");
1833
+ if (fs3.existsSync(TASK_MEMORY_FILE)) {
1834
+ const data = fs3.readFileSync(TASK_MEMORY_FILE, "utf-8");
1787
1835
  return JSON.parse(data);
1788
1836
  }
1789
1837
  } catch {
@@ -1809,11 +1857,11 @@ function saveTaskPattern(input, steps) {
1809
1857
  });
1810
1858
  }
1811
1859
  memory.patterns = memory.patterns.sort((a, b) => b.successCount - a.successCount).slice(0, 100);
1812
- const dir = path.dirname(TASK_MEMORY_FILE);
1813
- if (!fs2.existsSync(dir)) {
1814
- fs2.mkdirSync(dir, { recursive: true });
1860
+ const dir = path2.dirname(TASK_MEMORY_FILE);
1861
+ if (!fs3.existsSync(dir)) {
1862
+ fs3.mkdirSync(dir, { recursive: true });
1815
1863
  }
1816
- fs2.writeFileSync(TASK_MEMORY_FILE, JSON.stringify(memory, null, 2));
1864
+ fs3.writeFileSync(TASK_MEMORY_FILE, JSON.stringify(memory, null, 2));
1817
1865
  } catch {
1818
1866
  }
1819
1867
  }
@@ -2654,8 +2702,8 @@ function getTaskMemoryStats() {
2654
2702
  }
2655
2703
  function clearTaskMemory() {
2656
2704
  try {
2657
- if (fs2.existsSync(TASK_MEMORY_FILE)) {
2658
- fs2.unlinkSync(TASK_MEMORY_FILE);
2705
+ if (fs3.existsSync(TASK_MEMORY_FILE)) {
2706
+ fs3.unlinkSync(TASK_MEMORY_FILE);
2659
2707
  }
2660
2708
  } catch {
2661
2709
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@projectservan8n/cnapse",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
4
4
  "description": "Autonomous PC intelligence - AI assistant for desktop automation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -7,9 +7,14 @@
7
7
  * - Email (Gmail, Outlook)
8
8
  * - Google Sheets/Docs
9
9
  * - General web browsing
10
+ *
11
+ * Uses your system Chrome with existing logins and profile!
10
12
  */
11
13
 
12
14
  import { chromium, Browser, Page, BrowserContext } from 'playwright';
15
+ import * as path from 'path';
16
+ import * as os from 'os';
17
+ import * as fs from 'fs';
13
18
 
14
19
  // Singleton browser instance
15
20
  let browser: Browser | null = null;
@@ -21,35 +26,96 @@ interface BrowserConfig {
21
26
  headless: boolean;
22
27
  slowMo: number;
23
28
  viewport: { width: number; height: number };
29
+ useSystemBrowser: boolean; // Use system Chrome with your profile
24
30
  }
25
31
 
26
32
  const defaultConfig: BrowserConfig = {
27
33
  headless: false, // Show browser so user can see what's happening
28
34
  slowMo: 50, // Slight delay for visibility
29
- viewport: { width: 1280, height: 800 }
35
+ viewport: { width: 1280, height: 800 },
36
+ useSystemBrowser: true // Default to using system Chrome
30
37
  };
31
38
 
39
+ /**
40
+ * Find Chrome/Edge executable on Windows
41
+ */
42
+ function findSystemBrowser(): string | null {
43
+ const possiblePaths = [
44
+ // Chrome paths
45
+ path.join(process.env['PROGRAMFILES'] || '', 'Google', 'Chrome', 'Application', 'chrome.exe'),
46
+ path.join(process.env['PROGRAMFILES(X86)'] || '', 'Google', 'Chrome', 'Application', 'chrome.exe'),
47
+ path.join(process.env['LOCALAPPDATA'] || '', 'Google', 'Chrome', 'Application', 'chrome.exe'),
48
+ // Edge paths (fallback)
49
+ path.join(process.env['PROGRAMFILES'] || '', 'Microsoft', 'Edge', 'Application', 'msedge.exe'),
50
+ path.join(process.env['PROGRAMFILES(X86)'] || '', 'Microsoft', 'Edge', 'Application', 'msedge.exe'),
51
+ ];
52
+
53
+ for (const browserPath of possiblePaths) {
54
+ if (fs.existsSync(browserPath)) {
55
+ return browserPath;
56
+ }
57
+ }
58
+ return null;
59
+ }
60
+
61
+ /**
62
+ * Get Chrome user data directory
63
+ */
64
+ function getChromeUserDataDir(): string {
65
+ // Use a separate profile to avoid conflicts with running Chrome
66
+ const cnapseProfile = path.join(os.homedir(), '.cnapse', 'chrome-profile');
67
+
68
+ // Create if doesn't exist
69
+ if (!fs.existsSync(cnapseProfile)) {
70
+ fs.mkdirSync(cnapseProfile, { recursive: true });
71
+ }
72
+
73
+ return cnapseProfile;
74
+ }
75
+
32
76
  /**
33
77
  * Initialize browser if not already running
78
+ * Uses system Chrome with persistent profile (keeps your logins!)
34
79
  */
35
80
  export async function initBrowser(config: Partial<BrowserConfig> = {}): Promise<Page> {
36
81
  const cfg = { ...defaultConfig, ...config };
37
82
 
38
- if (!browser) {
39
- browser = await chromium.launch({
40
- headless: cfg.headless,
41
- slowMo: cfg.slowMo,
42
- });
43
- }
44
-
45
83
  if (!context) {
46
- context = await browser.newContext({
47
- viewport: cfg.viewport,
48
- userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
49
- });
84
+ const browserPath = cfg.useSystemBrowser ? findSystemBrowser() : null;
85
+ const userDataDir = getChromeUserDataDir();
86
+
87
+ if (browserPath && cfg.useSystemBrowser) {
88
+ // Use persistent context with system Chrome - keeps logins!
89
+ context = await chromium.launchPersistentContext(userDataDir, {
90
+ headless: cfg.headless,
91
+ slowMo: cfg.slowMo,
92
+ viewport: cfg.viewport,
93
+ executablePath: browserPath,
94
+ channel: undefined, // Don't use channel when specifying executablePath
95
+ args: [
96
+ '--disable-blink-features=AutomationControlled', // Less bot detection
97
+ '--no-first-run',
98
+ '--no-default-browser-check',
99
+ ]
100
+ });
101
+ } else {
102
+ // Fallback to bundled Chromium with persistent context
103
+ context = await chromium.launchPersistentContext(userDataDir, {
104
+ headless: cfg.headless,
105
+ slowMo: cfg.slowMo,
106
+ viewport: cfg.viewport,
107
+ args: [
108
+ '--disable-blink-features=AutomationControlled',
109
+ ]
110
+ });
111
+ }
50
112
  }
51
113
 
52
- if (!activePage) {
114
+ // Get existing page or create new one
115
+ const pages = context.pages();
116
+ if (pages.length > 0) {
117
+ activePage = pages[0];
118
+ } else {
53
119
  activePage = await context.newPage();
54
120
  }
55
121
 
@@ -70,11 +136,14 @@ export async function getPage(): Promise<Page> {
70
136
  * Close browser
71
137
  */
72
138
  export async function closeBrowser(): Promise<void> {
139
+ if (context) {
140
+ await context.close();
141
+ context = null;
142
+ activePage = null;
143
+ }
73
144
  if (browser) {
74
145
  await browser.close();
75
146
  browser = null;
76
- context = null;
77
- activePage = null;
78
147
  }
79
148
  }
80
149