skopix 2.0.10 → 2.0.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/README.md ADDED
@@ -0,0 +1,126 @@
1
+ # Skopix
2
+
3
+ Record tests by using your app. Replay them anywhere.
4
+
5
+ **[skopix.ayteelabs.com](https://skopix.ayteelabs.com)**
6
+
7
+ ---
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install -g skopix
13
+ npx playwright install chromium
14
+ ```
15
+
16
+ ---
17
+
18
+ ## Quick Start
19
+
20
+ ### Solo mode
21
+ ```bash
22
+ skopix dashboard
23
+ ```
24
+ Open `http://localhost:9000` and start recording.
25
+
26
+ ### Team mode (one command)
27
+ Add to `~/.skopix.env` once:
28
+ ```
29
+ SKOPIX_SECRET_KEY=your-secret
30
+ SKOPIX_AGENT_EMAIL=your@email.com
31
+ SKOPIX_AGENT_PASSWORD=yourpassword
32
+ ```
33
+ Then:
34
+ ```bash
35
+ skopix start
36
+ ```
37
+ Starts the dashboard + agent in one command. Teammates connect via `http://YOUR-IP:9000`.
38
+
39
+ ### Teammates — connect as agent
40
+ ```bash
41
+ skopix agent --server http://HOST-IP:9000 --key "your-secret"
42
+ ```
43
+
44
+ ---
45
+
46
+ ## Configure AI
47
+
48
+ ```bash
49
+ skopix init
50
+ ```
51
+ Choose Gemini, OpenAI, or Ollama (local — no API key needed).
52
+
53
+ Or set manually in `~/.skopix.env`:
54
+ ```
55
+ SKOPIX_PROVIDER=gemini
56
+ GEMINI_API_KEY=your-key
57
+ ```
58
+
59
+ ---
60
+
61
+ ## All Commands
62
+
63
+ | Command | Description |
64
+ |---|---|
65
+ | `skopix start` | Start dashboard + agent (team mode) |
66
+ | `skopix dashboard` | Start dashboard (solo mode) |
67
+ | `skopix dashboard --team --host 0.0.0.0` | Start dashboard in team mode |
68
+ | `skopix agent --server URL --key SECRET` | Connect as agent to a shared server |
69
+ | `skopix init` | Configure AI provider and API keys |
70
+ | `skopix config --set KEY=value` | Set a config value |
71
+ | `skopix config --list` | List all config values |
72
+
73
+ ---
74
+
75
+ ## Data & Backup
76
+
77
+ All data lives in `~/.skopix/` — tests, suites, sessions, credentials.
78
+
79
+ Backup:
80
+ ```bash
81
+ node skopix-backup.js
82
+ ```
83
+ Restore:
84
+ ```bash
85
+ node skopix-restore.js
86
+ ```
87
+ Download backup scripts from this repo.
88
+
89
+ ---
90
+
91
+ ## Remote Access
92
+
93
+ Expose your dashboard to remote teammates using [Portix](https://portix.dev):
94
+ ```bash
95
+ portix 9000 --name skopix
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Export to Playwright
101
+
102
+ Every recorded test generates a `.spec.js` / `.spec.ts` file. Download it from the test editor and run it anywhere with:
103
+ ```bash
104
+ npx playwright test
105
+ ```
106
+ No Skopix needed to run exported tests.
107
+
108
+ ---
109
+
110
+ ## Environment Variables
111
+
112
+ | Variable | Description |
113
+ |---|---|
114
+ | `SKOPIX_SECRET_KEY` | Required for team mode |
115
+ | `SKOPIX_PROVIDER` | AI provider: `gemini`, `openai`, `ollama` |
116
+ | `GEMINI_API_KEY` | Google Gemini API key |
117
+ | `OPENAI_API_KEY` | OpenAI API key |
118
+ | `OLLAMA_MODEL` | Ollama model name (e.g. `llama3.1`) |
119
+ | `SKOPIX_AGENT_EMAIL` | Auto-agent login email |
120
+ | `SKOPIX_AGENT_PASSWORD` | Auto-agent login password |
121
+ | `BASE_URL` | Override base URL for exported Playwright tests |
122
+ | `TEST_PASSWORD` | Password used in exported Playwright tests |
123
+
124
+ ---
125
+
126
+ Built by [Aytee Labs](https://ayteelabs.com)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skopix",
3
- "version": "2.0.10",
3
+ "version": "2.0.12",
4
4
  "description": "Browser-based QA tool — record tests by using your app, replay them deterministically, generate Playwright code automatically",
5
5
  "main": "cli/index.js",
6
6
  "bin": {
@@ -0,0 +1,5 @@
1
+ #!/bin/bash
2
+ node ~/Downloads/skopix_backup/skopix-backup.js
3
+ echo ""
4
+ echo "Press any key to close..."
5
+ read -n 1
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env node
2
+ // ─────────────────────────────────────────────────────────────────
3
+ // SKOPIX BACKUP
4
+ // Works on Mac, Windows, and Linux — no dependencies needed.
5
+ // Usage: node skopix-backup.js
6
+ // ─────────────────────────────────────────────────────────────────
7
+ import fs from 'fs';
8
+ import path from 'path';
9
+ import os from 'os';
10
+ import { execSync } from 'child_process';
11
+
12
+ const SKOPIX_DIR = path.join(os.homedir(), '.skopix');
13
+ const TODAY = new Date().toISOString().slice(0, 10);
14
+ const BACKUP_NAME = `skopix-backup-${TODAY}.zip`;
15
+ const DESKTOP = path.join(os.homedir(), 'Desktop');
16
+ const DEST = path.join(DESKTOP, BACKUP_NAME);
17
+
18
+ const c = {
19
+ cyan: (s) => `\x1b[36m${s}\x1b[0m`,
20
+ green: (s) => `\x1b[32m${s}\x1b[0m`,
21
+ red: (s) => `\x1b[31m${s}\x1b[0m`,
22
+ dim: (s) => `\x1b[2m${s}\x1b[0m`,
23
+ bold: (s) => `\x1b[1m${s}\x1b[0m`,
24
+ };
25
+
26
+ function countFiles(dir) {
27
+ let count = 0;
28
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
29
+ if (entry.isDirectory()) count += countFiles(path.join(dir, entry.name));
30
+ else count++;
31
+ }
32
+ return count;
33
+ }
34
+
35
+ function formatBytes(bytes) {
36
+ if (bytes < 1024) return bytes + ' B';
37
+ if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
38
+ return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
39
+ }
40
+
41
+ function dirSize(dir) {
42
+ let total = 0;
43
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
44
+ const p = path.join(dir, entry.name);
45
+ if (entry.isDirectory()) total += dirSize(p);
46
+ else total += fs.statSync(p).size;
47
+ }
48
+ return total;
49
+ }
50
+
51
+ console.log('');
52
+ console.log(c.cyan(c.bold(' SKOPIX BACKUP')));
53
+ console.log(' ' + c.dim('─'.repeat(50)));
54
+
55
+ if (!fs.existsSync(SKOPIX_DIR)) {
56
+ console.log(' ' + c.red('✖') + ' ~/.skopix not found — nothing to back up');
57
+ process.exit(1);
58
+ }
59
+
60
+ const fileCount = countFiles(SKOPIX_DIR);
61
+ const size = formatBytes(dirSize(SKOPIX_DIR));
62
+ console.log(' Source : ' + c.cyan(SKOPIX_DIR));
63
+ console.log(' Files : ' + fileCount + ' files (' + size + ')');
64
+ console.log(' Saving : ' + c.cyan(DEST));
65
+ console.log('');
66
+
67
+ if (fs.existsSync(DEST)) fs.unlinkSync(DEST);
68
+
69
+ try {
70
+ const isWindows = process.platform === 'win32';
71
+ if (isWindows) {
72
+ const ps = `Compress-Archive -Path "${SKOPIX_DIR}\\*" -DestinationPath "${DEST}" -Force`;
73
+ execSync(`powershell -Command "${ps}"`, { stdio: 'pipe' });
74
+ } else {
75
+ execSync(`cd "${os.homedir()}" && zip -r "${DEST}" .skopix`, { stdio: 'pipe' });
76
+ }
77
+ console.log(' ' + c.green('✔') + ' Backup saved to:');
78
+ console.log(' ' + c.cyan(DEST));
79
+ console.log('');
80
+ console.log(' ' + c.dim('Restore with: node skopix-restore.js'));
81
+ console.log('');
82
+ } catch (e) {
83
+ console.log(' ' + c.red('✖') + ' Backup failed: ' + e.message);
84
+ process.exit(1);
85
+ }
@@ -0,0 +1,5 @@
1
+ #!/bin/bash
2
+ node ~/Downloads/skopix_backup/skopix-restore.js
3
+ echo ""
4
+ echo "Press any key to close..."
5
+ read -n 1
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env node
2
+ // ─────────────────────────────────────────────────────────────────
3
+ // SKOPIX RESTORE
4
+ // Works on Mac, Windows, and Linux — no dependencies needed.
5
+ // Usage: node skopix-restore.js
6
+ // or: node skopix-restore.js /path/to/skopix-backup-2026-05-26.zip
7
+ // ─────────────────────────────────────────────────────────────────
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import os from 'os';
11
+ import { execSync } from 'child_process';
12
+ import readline from 'readline';
13
+
14
+ const SKOPIX_DIR = path.join(os.homedir(), '.skopix');
15
+
16
+ const c = {
17
+ cyan: (s) => `\x1b[36m${s}\x1b[0m`,
18
+ green: (s) => `\x1b[32m${s}\x1b[0m`,
19
+ yellow: (s) => `\x1b[33m${s}\x1b[0m`,
20
+ red: (s) => `\x1b[31m${s}\x1b[0m`,
21
+ dim: (s) => `\x1b[2m${s}\x1b[0m`,
22
+ bold: (s) => `\x1b[1m${s}\x1b[0m`,
23
+ };
24
+
25
+ function ask(question) {
26
+ return new Promise(resolve => {
27
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
28
+ rl.question(' ' + question, ans => { rl.close(); resolve(ans.trim()); });
29
+ });
30
+ }
31
+
32
+ function copyDir(src, dest) {
33
+ fs.mkdirSync(dest, { recursive: true });
34
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
35
+ const s = path.join(src, entry.name);
36
+ const d = path.join(dest, entry.name);
37
+ if (entry.isDirectory()) copyDir(s, d);
38
+ else fs.copyFileSync(s, d);
39
+ }
40
+ }
41
+
42
+ function countFiles(dir) {
43
+ let count = 0;
44
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
45
+ if (entry.isDirectory()) count += countFiles(path.join(dir, entry.name));
46
+ else count++;
47
+ }
48
+ return count;
49
+ }
50
+
51
+ function findBackups() {
52
+ const searchDirs = [
53
+ path.join(os.homedir(), 'Desktop'),
54
+ path.join(os.homedir(), 'Downloads'),
55
+ os.homedir(),
56
+ process.cwd(),
57
+ ];
58
+ const found = [];
59
+ for (const dir of searchDirs) {
60
+ if (!fs.existsSync(dir)) continue;
61
+ for (const f of fs.readdirSync(dir)) {
62
+ if (f.startsWith('skopix-backup') && f.endsWith('.zip')) {
63
+ found.push(path.join(dir, f));
64
+ }
65
+ }
66
+ }
67
+ return found;
68
+ }
69
+
70
+ console.log('');
71
+ console.log(c.cyan(c.bold(' SKOPIX RESTORE')));
72
+ console.log(' ' + c.dim('─'.repeat(50)));
73
+
74
+ // Find backup file
75
+ let src = process.argv[2];
76
+
77
+ if (!src) {
78
+ const found = findBackups();
79
+ if (found.length === 0) {
80
+ console.log(' ' + c.red('✖') + ' No backup files found on Desktop or Downloads.');
81
+ console.log(' Run: node skopix-restore.js /path/to/backup.zip');
82
+ process.exit(1);
83
+ } else if (found.length === 1) {
84
+ src = found[0];
85
+ console.log(' Found: ' + c.cyan(src));
86
+ } else {
87
+ console.log(' Found multiple backups:');
88
+ found.forEach((f, i) => console.log(' ' + (i + 1) + '. ' + f));
89
+ const choice = await ask('Which one to restore? (1-' + found.length + '): ');
90
+ const idx = parseInt(choice) - 1;
91
+ if (isNaN(idx) || idx < 0 || idx >= found.length) {
92
+ console.log(' ' + c.red('✖') + ' Invalid choice'); process.exit(1);
93
+ }
94
+ src = found[idx];
95
+ }
96
+ }
97
+
98
+ if (!fs.existsSync(src)) {
99
+ console.log(' ' + c.red('✖') + ' File not found: ' + src);
100
+ process.exit(1);
101
+ }
102
+
103
+ console.log(' Backup : ' + c.cyan(src));
104
+ console.log('');
105
+
106
+ // Warn about overwrite
107
+ if (fs.existsSync(SKOPIX_DIR)) {
108
+ const existing = countFiles(SKOPIX_DIR);
109
+ console.log(' ' + c.yellow('⚠') + ' This will overwrite ~/.skopix (' + existing + ' files)');
110
+ const confirm = await ask('Continue? (y/N): ');
111
+ if (confirm.toLowerCase() !== 'y') {
112
+ console.log(' ' + c.yellow('⚠') + ' Restore cancelled.');
113
+ process.exit(0);
114
+ }
115
+
116
+ // Auto-backup existing data first
117
+ const autoBackup = path.join(os.tmpdir(), 'skopix-pre-restore-' + Date.now());
118
+ copyDir(SKOPIX_DIR, autoBackup);
119
+ console.log(' ' + c.dim('Auto-backed up existing data to: ' + autoBackup));
120
+ }
121
+
122
+ console.log(' Restoring...');
123
+
124
+ try {
125
+ const tmpDir = path.join(os.tmpdir(), 'skopix-restore-' + Date.now());
126
+ fs.mkdirSync(tmpDir, { recursive: true });
127
+
128
+ const isWindows = process.platform === 'win32';
129
+ if (isWindows) {
130
+ const ps = `Expand-Archive -Path "${src}" -DestinationPath "${tmpDir}" -Force`;
131
+ execSync(`powershell -Command "${ps}"`, { stdio: 'pipe' });
132
+ } else {
133
+ execSync(`unzip -o "${src}" -d "${tmpDir}"`, { stdio: 'pipe' });
134
+ }
135
+
136
+ // Find .skopix inside the extracted folder
137
+ const inner = path.join(tmpDir, '.skopix');
138
+ const actualSrc = fs.existsSync(inner) ? inner : tmpDir;
139
+
140
+ if (fs.existsSync(SKOPIX_DIR)) fs.rmSync(SKOPIX_DIR, { recursive: true, force: true });
141
+ copyDir(actualSrc, SKOPIX_DIR);
142
+ fs.rmSync(tmpDir, { recursive: true, force: true });
143
+
144
+ const restored = countFiles(SKOPIX_DIR);
145
+ console.log('');
146
+ console.log(' ' + c.green('✔') + ' Restored ' + restored + ' files to ' + c.cyan(SKOPIX_DIR));
147
+ console.log(' ' + c.green('✔') + ' Restart Skopix to see your data');
148
+ console.log('');
149
+ } catch (e) {
150
+ console.log(' ' + c.red('✖') + ' Restore failed: ' + e.message);
151
+ process.exit(1);
152
+ }