uniner-cli 1.0.10 → 1.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 +10 -1
- package/lib/SKILL.md.template +1 -1
- package/package.json +1 -1
- package/scripts/cleanup.js +123 -123
- package/scripts/preuninstall.js +25 -25
package/README.md
CHANGED
|
@@ -61,6 +61,7 @@ uniner-cli --help
|
|
|
61
61
|
uniner-cli web browser open --url "https://example.com"
|
|
62
62
|
uniner-cli web element click --xpath "//button[@id='submit']"
|
|
63
63
|
uniner-cli web element get-text --xpath "//h1"
|
|
64
|
+
uniner-cli web action pdf --output report.pdf
|
|
64
65
|
|
|
65
66
|
# Excel
|
|
66
67
|
uniner-cli excel data read --file data.xlsx --cell A1
|
|
@@ -178,7 +179,15 @@ npm install -g uniner-cli
|
|
|
178
179
|
|
|
179
180
|
## Changelog
|
|
180
181
|
|
|
181
|
-
### 1.
|
|
182
|
+
### 1.0.11 (2026-07-16)
|
|
183
|
+
|
|
184
|
+
- **feat**: 新增 `web action pdf` 命令,支持将当前网页导出为 PDF(纸张格式 / 横向 / 背景 / 页边距 / 页眉页脚 / 缩放 / 页面范围)。SDK 层新增 `chrome.pdf()` 方法。
|
|
185
|
+
|
|
186
|
+
### 1.0.10 (2026-07-10)
|
|
187
|
+
|
|
188
|
+
- **feat**: 优化 Windows 端用户体验
|
|
189
|
+
|
|
190
|
+
### 1.0.9 (2026-07-05)
|
|
182
191
|
|
|
183
192
|
- **feat**: SDK 1.24.0 同步 —— 新增 `tool ftp` 子命令(create-folder / check-folder / check-file / list-dir),跨平台可用
|
|
184
193
|
- **feat**: `web browser close` 现在自动终止残留 chrome.exe 进程,避免进程泄漏
|
package/lib/SKILL.md.template
CHANGED
|
@@ -64,7 +64,7 @@ web 浏览器自动化(Playwright + CDP)
|
|
|
64
64
|
├── element click / input / get-text / get-value / select / check / hover / screenshot
|
|
65
65
|
├── iframe enter / exit / list
|
|
66
66
|
├── page list / switch / close
|
|
67
|
-
└── action screenshot / execute-js / get-cookie / set-cookie
|
|
67
|
+
└── action screenshot / pdf / execute-js / get-cookie / set-cookie
|
|
68
68
|
|
|
69
69
|
tool 通用工具
|
|
70
70
|
├── list 创建 / append / remove / find / sort / unique
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uniner-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
4
4
|
"description": "uniner-cli — RPA automation CLI: browser automation (Playwright/CDP), Excel, OCR, desktop/SAP, crypto/HTTP/email tools. Auto-installs a Claude Code skill on install.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"rpa",
|
package/scripts/cleanup.js
CHANGED
|
@@ -1,123 +1,123 @@
|
|
|
1
|
-
// Shared cleanup logic for uninstall.
|
|
2
|
-
// Extracted so both the npm lifecycle hook (preuninstall.js) and the
|
|
3
|
-
// manual command (bin/uniner-cli-uninstall.js) can share it.
|
|
4
|
-
|
|
5
|
-
'use strict';
|
|
6
|
-
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
|
|
10
|
-
const {
|
|
11
|
-
rootDir,
|
|
12
|
-
skillDir,
|
|
13
|
-
skillFile,
|
|
14
|
-
} = require('../lib/paths');
|
|
15
|
-
|
|
16
|
-
function rmRf(p) {
|
|
17
|
-
try {
|
|
18
|
-
if (fs.existsSync(p)) {
|
|
19
|
-
fs.rmSync(p, { recursive: true, force: true });
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
return false;
|
|
23
|
-
} catch (_) {
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function rmFile(p) {
|
|
29
|
-
try {
|
|
30
|
-
if (fs.existsSync(p)) {
|
|
31
|
-
fs.unlinkSync(p);
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
return false;
|
|
35
|
-
} catch (_) {
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Run the full uninstall cleanup.
|
|
42
|
-
*
|
|
43
|
-
* @param {object} [opts]
|
|
44
|
-
* @param {boolean} [opts.verbose=false] Print progress lines to stdout.
|
|
45
|
-
* The preuninstall hook should pass false
|
|
46
|
-
* because npm swallows lifecycle output
|
|
47
|
-
* unless --verbose is used; the manual
|
|
48
|
-
* command passes true so the user sees
|
|
49
|
-
* what happened.
|
|
50
|
-
* @returns {{ didSomething: boolean, scenariosKept: number, scenariosDir: string|null }}
|
|
51
|
-
*/
|
|
52
|
-
function cleanup(opts) {
|
|
53
|
-
const verbose = (opts && opts.verbose) || false;
|
|
54
|
-
|
|
55
|
-
function log(msg) {
|
|
56
|
-
if (verbose) {
|
|
57
|
-
console.log(`[uniner-cli] ${msg}`);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const root = rootDir();
|
|
62
|
-
let didSomething = false;
|
|
63
|
-
|
|
64
|
-
// 1. Remove the entire ~/.uniner-cli/ tree (all versions).
|
|
65
|
-
// The version-specific layout exists so the installer can support
|
|
66
|
-
// multi-version coexistence, but on uninstall the user wants a full
|
|
67
|
-
// removal — orphaned old version dirs would just waste disk space.
|
|
68
|
-
if (rmRf(root)) {
|
|
69
|
-
log(`Removed ${root}`);
|
|
70
|
-
didSomething = true;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// 2. Remove ONLY the SKILL.md file. NEVER rm -rf the whole skill dir,
|
|
74
|
-
// because the user's accumulated scenarios/<name>/ subdirectories
|
|
75
|
-
// live there and represent real work they've sedimented over time.
|
|
76
|
-
const dir = skillDir();
|
|
77
|
-
if (rmFile(skillFile())) {
|
|
78
|
-
log(`Removed ${skillFile()}`);
|
|
79
|
-
didSomething = true;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// 3. Count scenarios/ subdirs that contain a meta.json.
|
|
83
|
-
let scenariosKept = 0;
|
|
84
|
-
const scenariosPath = path.join(dir, 'scenarios');
|
|
85
|
-
if (fs.existsSync(scenariosPath)) {
|
|
86
|
-
try {
|
|
87
|
-
scenariosKept = fs.readdirSync(scenariosPath).filter(n => {
|
|
88
|
-
const meta = path.join(scenariosPath, n, 'meta.json');
|
|
89
|
-
return fs.existsSync(meta);
|
|
90
|
-
}).length;
|
|
91
|
-
} catch (_) {
|
|
92
|
-
// best-effort
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// 4. If skill dir is now genuinely empty, remove it. Otherwise keep it.
|
|
97
|
-
try {
|
|
98
|
-
if (fs.existsSync(dir)) {
|
|
99
|
-
const remaining = fs.readdirSync(dir);
|
|
100
|
-
if (remaining.length === 0) {
|
|
101
|
-
fs.rmdirSync(dir);
|
|
102
|
-
log(`Removed empty ${dir}`);
|
|
103
|
-
didSomething = true;
|
|
104
|
-
} else if (verbose) {
|
|
105
|
-
log(`Keeping ${dir} (${scenariosKept} scenario(s) preserved)`);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
} catch (_) {
|
|
109
|
-
// best-effort
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (!didSomething) {
|
|
113
|
-
log('Nothing to clean — already removed.');
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return {
|
|
117
|
-
didSomething,
|
|
118
|
-
scenariosKept,
|
|
119
|
-
scenariosDir: scenariosKept > 0 ? scenariosPath : null,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
module.exports = { cleanup };
|
|
1
|
+
// Shared cleanup logic for uninstall.
|
|
2
|
+
// Extracted so both the npm lifecycle hook (preuninstall.js) and the
|
|
3
|
+
// manual command (bin/uniner-cli-uninstall.js) can share it.
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
const {
|
|
11
|
+
rootDir,
|
|
12
|
+
skillDir,
|
|
13
|
+
skillFile,
|
|
14
|
+
} = require('../lib/paths');
|
|
15
|
+
|
|
16
|
+
function rmRf(p) {
|
|
17
|
+
try {
|
|
18
|
+
if (fs.existsSync(p)) {
|
|
19
|
+
fs.rmSync(p, { recursive: true, force: true });
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
} catch (_) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function rmFile(p) {
|
|
29
|
+
try {
|
|
30
|
+
if (fs.existsSync(p)) {
|
|
31
|
+
fs.unlinkSync(p);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
} catch (_) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Run the full uninstall cleanup.
|
|
42
|
+
*
|
|
43
|
+
* @param {object} [opts]
|
|
44
|
+
* @param {boolean} [opts.verbose=false] Print progress lines to stdout.
|
|
45
|
+
* The preuninstall hook should pass false
|
|
46
|
+
* because npm swallows lifecycle output
|
|
47
|
+
* unless --verbose is used; the manual
|
|
48
|
+
* command passes true so the user sees
|
|
49
|
+
* what happened.
|
|
50
|
+
* @returns {{ didSomething: boolean, scenariosKept: number, scenariosDir: string|null }}
|
|
51
|
+
*/
|
|
52
|
+
function cleanup(opts) {
|
|
53
|
+
const verbose = (opts && opts.verbose) || false;
|
|
54
|
+
|
|
55
|
+
function log(msg) {
|
|
56
|
+
if (verbose) {
|
|
57
|
+
console.log(`[uniner-cli] ${msg}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const root = rootDir();
|
|
62
|
+
let didSomething = false;
|
|
63
|
+
|
|
64
|
+
// 1. Remove the entire ~/.uniner-cli/ tree (all versions).
|
|
65
|
+
// The version-specific layout exists so the installer can support
|
|
66
|
+
// multi-version coexistence, but on uninstall the user wants a full
|
|
67
|
+
// removal — orphaned old version dirs would just waste disk space.
|
|
68
|
+
if (rmRf(root)) {
|
|
69
|
+
log(`Removed ${root}`);
|
|
70
|
+
didSomething = true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 2. Remove ONLY the SKILL.md file. NEVER rm -rf the whole skill dir,
|
|
74
|
+
// because the user's accumulated scenarios/<name>/ subdirectories
|
|
75
|
+
// live there and represent real work they've sedimented over time.
|
|
76
|
+
const dir = skillDir();
|
|
77
|
+
if (rmFile(skillFile())) {
|
|
78
|
+
log(`Removed ${skillFile()}`);
|
|
79
|
+
didSomething = true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 3. Count scenarios/ subdirs that contain a meta.json.
|
|
83
|
+
let scenariosKept = 0;
|
|
84
|
+
const scenariosPath = path.join(dir, 'scenarios');
|
|
85
|
+
if (fs.existsSync(scenariosPath)) {
|
|
86
|
+
try {
|
|
87
|
+
scenariosKept = fs.readdirSync(scenariosPath).filter(n => {
|
|
88
|
+
const meta = path.join(scenariosPath, n, 'meta.json');
|
|
89
|
+
return fs.existsSync(meta);
|
|
90
|
+
}).length;
|
|
91
|
+
} catch (_) {
|
|
92
|
+
// best-effort
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 4. If skill dir is now genuinely empty, remove it. Otherwise keep it.
|
|
97
|
+
try {
|
|
98
|
+
if (fs.existsSync(dir)) {
|
|
99
|
+
const remaining = fs.readdirSync(dir);
|
|
100
|
+
if (remaining.length === 0) {
|
|
101
|
+
fs.rmdirSync(dir);
|
|
102
|
+
log(`Removed empty ${dir}`);
|
|
103
|
+
didSomething = true;
|
|
104
|
+
} else if (verbose) {
|
|
105
|
+
log(`Keeping ${dir} (${scenariosKept} scenario(s) preserved)`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} catch (_) {
|
|
109
|
+
// best-effort
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!didSomething) {
|
|
113
|
+
log('Nothing to clean — already removed.');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
didSomething,
|
|
118
|
+
scenariosKept,
|
|
119
|
+
scenariosDir: scenariosKept > 0 ? scenariosPath : null,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
module.exports = { cleanup };
|
package/scripts/preuninstall.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// preuninstall.js — npm lifecycle hook, runs automatically on
|
|
3
|
-
// `npm uninstall -g uniner-cli`.
|
|
4
|
-
//
|
|
5
|
-
// Cleans up the runtime tree (~/.uniner-cli/<version>/) and the skill file
|
|
6
|
-
// (~/.claude/skills/uniner-cli/SKILL.md). Preserves user scenarios under
|
|
7
|
-
// ~/.claude/skills/uniner-cli/scenarios/ — those represent accumulated
|
|
8
|
-
// knowledge and are never deleted automatically.
|
|
9
|
-
//
|
|
10
|
-
// IMPORTANT: This script MUST exit 0 in all cases, otherwise it would
|
|
11
|
-
// abort the user's `npm uninstall`. Errors are swallowed silently.
|
|
12
|
-
//
|
|
13
|
-
// The manual `uniner-cli-uninstall` command is still useful for users who
|
|
14
|
-
// want verbose feedback, or who want to clean up before the npm package is
|
|
15
|
-
// gone (e.g. if the hook somehow didn't fire).
|
|
16
|
-
|
|
17
|
-
'use strict';
|
|
18
|
-
|
|
19
|
-
const { cleanup } = require('./cleanup');
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
cleanup({ verbose: false });
|
|
23
|
-
} catch (_) {
|
|
24
|
-
// Never fail the uninstall — swallow all errors.
|
|
25
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// preuninstall.js — npm lifecycle hook, runs automatically on
|
|
3
|
+
// `npm uninstall -g uniner-cli`.
|
|
4
|
+
//
|
|
5
|
+
// Cleans up the runtime tree (~/.uniner-cli/<version>/) and the skill file
|
|
6
|
+
// (~/.claude/skills/uniner-cli/SKILL.md). Preserves user scenarios under
|
|
7
|
+
// ~/.claude/skills/uniner-cli/scenarios/ — those represent accumulated
|
|
8
|
+
// knowledge and are never deleted automatically.
|
|
9
|
+
//
|
|
10
|
+
// IMPORTANT: This script MUST exit 0 in all cases, otherwise it would
|
|
11
|
+
// abort the user's `npm uninstall`. Errors are swallowed silently.
|
|
12
|
+
//
|
|
13
|
+
// The manual `uniner-cli-uninstall` command is still useful for users who
|
|
14
|
+
// want verbose feedback, or who want to clean up before the npm package is
|
|
15
|
+
// gone (e.g. if the hook somehow didn't fire).
|
|
16
|
+
|
|
17
|
+
'use strict';
|
|
18
|
+
|
|
19
|
+
const { cleanup } = require('./cleanup');
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
cleanup({ verbose: false });
|
|
23
|
+
} catch (_) {
|
|
24
|
+
// Never fail the uninstall — swallow all errors.
|
|
25
|
+
}
|