@jackwener/opencli 0.9.5 → 0.9.8
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/.github/ISSUE_TEMPLATE/bug_report.yml +83 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +42 -0
- package/.github/ISSUE_TEMPLATE/new_site_adapter.yml +57 -0
- package/.github/dependabot.yml +27 -0
- package/.github/pull_request_template.md +24 -0
- package/.github/workflows/ci.yml +14 -8
- package/.github/workflows/e2e-headed.yml +6 -2
- package/.github/workflows/pkg-pr-new.yml +2 -2
- package/.github/workflows/release-please.yml +25 -0
- package/.github/workflows/release.yml +2 -2
- package/.github/workflows/security.yml +36 -0
- package/CLI-ELECTRON.md +89 -36
- package/CONTRIBUTING.md +167 -0
- package/README.md +98 -32
- package/README.zh-CN.md +99 -33
- package/dist/browser/discover.js +22 -7
- package/dist/browser.test.js +23 -0
- package/dist/build-manifest.d.ts +26 -0
- package/dist/build-manifest.js +132 -60
- package/dist/build-manifest.test.d.ts +1 -0
- package/dist/build-manifest.test.js +26 -0
- package/dist/cli-manifest.json +1875 -271
- package/dist/clis/antigravity/model.js +2 -2
- package/dist/clis/antigravity/send.js +2 -2
- package/dist/clis/bilibili/download.d.ts +10 -0
- package/dist/clis/bilibili/download.js +135 -0
- package/dist/clis/chatgpt/ask.d.ts +1 -0
- package/dist/clis/chatgpt/ask.js +68 -0
- package/dist/clis/chatgpt/send.js +11 -0
- package/dist/clis/chatwise/ask.d.ts +1 -0
- package/dist/clis/chatwise/ask.js +76 -0
- package/dist/clis/chatwise/export.d.ts +1 -0
- package/dist/clis/chatwise/export.js +46 -0
- package/dist/clis/chatwise/history.d.ts +1 -0
- package/dist/clis/chatwise/history.js +43 -0
- package/dist/clis/chatwise/model.d.ts +1 -0
- package/dist/clis/chatwise/model.js +81 -0
- package/dist/clis/chatwise/new.d.ts +1 -0
- package/dist/clis/chatwise/new.js +18 -0
- package/dist/clis/chatwise/read.d.ts +1 -0
- package/dist/clis/chatwise/read.js +39 -0
- package/dist/clis/chatwise/screenshot.d.ts +1 -0
- package/dist/clis/chatwise/screenshot.js +27 -0
- package/dist/clis/chatwise/send.d.ts +1 -0
- package/dist/clis/chatwise/send.js +45 -0
- package/dist/clis/chatwise/status.d.ts +1 -0
- package/dist/clis/chatwise/status.js +22 -0
- package/dist/clis/codex/ask.d.ts +1 -0
- package/dist/clis/codex/ask.js +67 -0
- package/dist/clis/codex/export.d.ts +1 -0
- package/dist/clis/codex/export.js +37 -0
- package/dist/clis/codex/history.d.ts +1 -0
- package/dist/clis/codex/history.js +43 -0
- package/dist/clis/codex/read.js +3 -5
- package/dist/clis/codex/screenshot.d.ts +1 -0
- package/dist/clis/codex/screenshot.js +27 -0
- package/dist/clis/codex/send.js +3 -6
- package/dist/clis/codex/status.js +2 -1
- package/dist/clis/cursor/ask.d.ts +1 -0
- package/dist/clis/cursor/ask.js +69 -0
- package/dist/clis/cursor/composer.js +9 -28
- package/dist/clis/cursor/export.d.ts +1 -0
- package/dist/clis/cursor/export.js +51 -0
- package/dist/clis/cursor/history.d.ts +1 -0
- package/dist/clis/cursor/history.js +43 -0
- package/dist/clis/cursor/new.js +4 -13
- package/dist/clis/cursor/screenshot.d.ts +1 -0
- package/dist/clis/cursor/screenshot.js +31 -0
- package/dist/clis/discord-app/channels.d.ts +1 -0
- package/dist/clis/discord-app/channels.js +45 -0
- package/dist/clis/discord-app/members.d.ts +1 -0
- package/dist/clis/discord-app/members.js +38 -0
- package/dist/clis/discord-app/read.d.ts +1 -0
- package/dist/clis/discord-app/read.js +45 -0
- package/dist/clis/discord-app/search.d.ts +1 -0
- package/dist/clis/discord-app/search.js +56 -0
- package/dist/clis/discord-app/send.d.ts +1 -0
- package/dist/clis/discord-app/send.js +27 -0
- package/dist/clis/discord-app/servers.d.ts +1 -0
- package/dist/clis/discord-app/servers.js +36 -0
- package/dist/clis/discord-app/status.d.ts +1 -0
- package/dist/clis/discord-app/status.js +16 -0
- package/dist/clis/feishu/new.d.ts +1 -0
- package/dist/clis/feishu/new.js +27 -0
- package/dist/clis/feishu/read.d.ts +1 -0
- package/dist/clis/feishu/read.js +40 -0
- package/dist/clis/feishu/search.d.ts +1 -0
- package/dist/clis/feishu/search.js +30 -0
- package/dist/clis/feishu/send.d.ts +1 -0
- package/dist/clis/feishu/send.js +39 -0
- package/dist/clis/feishu/status.d.ts +1 -0
- package/dist/clis/feishu/status.js +28 -0
- package/dist/clis/grok/ask.d.ts +1 -0
- package/dist/clis/grok/ask.js +82 -0
- package/dist/clis/grok/debug.d.ts +1 -0
- package/dist/clis/grok/debug.js +45 -0
- package/dist/clis/jimeng/generate.yaml +84 -0
- package/dist/clis/jimeng/history.yaml +47 -0
- package/dist/clis/linux-do/categories.yaml +41 -0
- package/dist/clis/linux-do/category.yaml +49 -0
- package/dist/clis/linux-do/hot.yaml +50 -0
- package/dist/clis/linux-do/latest.yaml +40 -0
- package/dist/clis/linux-do/search.yaml +45 -0
- package/dist/clis/linux-do/topic.yaml +38 -0
- package/dist/clis/notion/export.d.ts +1 -0
- package/dist/clis/notion/export.js +31 -0
- package/dist/clis/notion/favorites.d.ts +1 -0
- package/dist/clis/notion/favorites.js +84 -0
- package/dist/clis/notion/new.d.ts +1 -0
- package/dist/clis/notion/new.js +34 -0
- package/dist/clis/notion/read.d.ts +1 -0
- package/dist/clis/notion/read.js +30 -0
- package/dist/clis/notion/search.d.ts +1 -0
- package/dist/clis/notion/search.js +46 -0
- package/dist/clis/notion/sidebar.d.ts +1 -0
- package/dist/clis/notion/sidebar.js +41 -0
- package/dist/clis/notion/status.d.ts +1 -0
- package/dist/clis/notion/status.js +16 -0
- package/dist/clis/notion/write.d.ts +1 -0
- package/dist/clis/notion/write.js +40 -0
- package/dist/clis/twitter/download.d.ts +8 -0
- package/dist/clis/twitter/download.js +204 -0
- package/dist/clis/wechat/chats.d.ts +1 -0
- package/dist/clis/wechat/chats.js +28 -0
- package/dist/clis/wechat/contacts.d.ts +1 -0
- package/dist/clis/wechat/contacts.js +28 -0
- package/dist/clis/wechat/read.d.ts +1 -0
- package/dist/clis/wechat/read.js +58 -0
- package/dist/clis/wechat/search.d.ts +1 -0
- package/dist/clis/wechat/search.js +31 -0
- package/dist/clis/wechat/send.d.ts +1 -0
- package/dist/clis/wechat/send.js +42 -0
- package/dist/clis/wechat/status.d.ts +1 -0
- package/dist/clis/wechat/status.js +29 -0
- package/dist/clis/xiaohongshu/creator-note-detail.d.ts +10 -0
- package/dist/clis/xiaohongshu/creator-note-detail.js +88 -0
- package/dist/clis/xiaohongshu/creator-notes.d.ts +11 -0
- package/dist/clis/xiaohongshu/creator-notes.js +109 -0
- package/dist/clis/xiaohongshu/creator-profile.d.ts +10 -0
- package/dist/clis/xiaohongshu/creator-profile.js +54 -0
- package/dist/clis/xiaohongshu/creator-stats.d.ts +10 -0
- package/dist/clis/xiaohongshu/creator-stats.js +74 -0
- package/dist/clis/xiaohongshu/download.d.ts +7 -0
- package/dist/clis/xiaohongshu/download.js +155 -0
- package/dist/clis/xiaohongshu/search.js +1 -1
- package/dist/clis/xiaohongshu/user-helpers.d.ts +15 -0
- package/dist/clis/xiaohongshu/user-helpers.js +67 -0
- package/dist/clis/xiaohongshu/user-helpers.test.d.ts +1 -0
- package/dist/clis/xiaohongshu/user-helpers.test.js +81 -0
- package/dist/clis/xiaohongshu/user.js +46 -29
- package/dist/clis/zhihu/download.d.ts +11 -0
- package/dist/clis/zhihu/download.js +186 -0
- package/dist/clis/zhihu/download.test.d.ts +1 -0
- package/dist/clis/zhihu/download.test.js +10 -0
- package/dist/download/index.d.ts +79 -0
- package/dist/download/index.js +325 -0
- package/dist/download/progress.d.ts +36 -0
- package/dist/download/progress.js +111 -0
- package/dist/engine.test.js +15 -0
- package/dist/main.js +16 -3
- package/dist/pipeline/registry.js +2 -0
- package/dist/pipeline/steps/download.d.ts +34 -0
- package/dist/pipeline/steps/download.js +251 -0
- package/dist/pipeline/template.js +28 -0
- package/package.json +4 -3
- package/scripts/test-site.mjs +70 -0
- package/src/browser/discover.ts +23 -7
- package/src/browser.test.ts +23 -0
- package/src/build-manifest.test.ts +28 -0
- package/src/build-manifest.ts +147 -57
- package/src/clis/antigravity/README.md +2 -3
- package/src/clis/antigravity/README.zh-CN.md +2 -3
- package/src/clis/antigravity/SKILL.md +1 -1
- package/src/clis/antigravity/model.ts +2 -2
- package/src/clis/antigravity/send.ts +2 -2
- package/src/clis/bilibili/download.ts +161 -0
- package/src/clis/chatgpt/README.md +25 -16
- package/src/clis/chatgpt/README.zh-CN.md +27 -18
- package/src/clis/chatgpt/ask.ts +77 -0
- package/src/clis/chatgpt/send.ts +12 -0
- package/src/clis/chatwise/README.md +38 -0
- package/src/clis/chatwise/README.zh-CN.md +38 -0
- package/src/clis/chatwise/ask.ts +87 -0
- package/src/clis/chatwise/export.ts +51 -0
- package/src/clis/chatwise/history.ts +47 -0
- package/src/clis/chatwise/model.ts +87 -0
- package/src/clis/chatwise/new.ts +21 -0
- package/src/clis/chatwise/read.ts +42 -0
- package/src/clis/chatwise/screenshot.ts +33 -0
- package/src/clis/chatwise/send.ts +50 -0
- package/src/clis/chatwise/status.ts +25 -0
- package/src/clis/codex/ask.ts +77 -0
- package/src/clis/codex/export.ts +42 -0
- package/src/clis/codex/extract-diff.ts +1 -0
- package/src/clis/codex/history.ts +47 -0
- package/src/clis/codex/read.ts +5 -6
- package/src/clis/codex/screenshot.ts +33 -0
- package/src/clis/codex/send.ts +6 -7
- package/src/clis/codex/status.ts +4 -2
- package/src/clis/cursor/ask.ts +81 -0
- package/src/clis/cursor/composer.ts +9 -30
- package/src/clis/cursor/export.ts +57 -0
- package/src/clis/cursor/history.ts +47 -0
- package/src/clis/cursor/new.ts +4 -15
- package/src/clis/cursor/screenshot.ts +38 -0
- package/src/clis/discord-app/README.md +28 -0
- package/src/clis/discord-app/README.zh-CN.md +28 -0
- package/src/clis/discord-app/channels.ts +48 -0
- package/src/clis/discord-app/members.ts +41 -0
- package/src/clis/discord-app/read.ts +49 -0
- package/src/clis/discord-app/search.ts +64 -0
- package/src/clis/discord-app/send.ts +32 -0
- package/src/clis/discord-app/servers.ts +39 -0
- package/src/clis/discord-app/status.ts +18 -0
- package/src/clis/feishu/README.md +20 -0
- package/src/clis/feishu/README.zh-CN.md +20 -0
- package/src/clis/feishu/new.ts +32 -0
- package/src/clis/feishu/read.ts +48 -0
- package/src/clis/feishu/search.ts +35 -0
- package/src/clis/feishu/send.ts +46 -0
- package/src/clis/feishu/status.ts +34 -0
- package/src/clis/grok/ask.ts +90 -0
- package/src/clis/grok/debug.ts +49 -0
- package/src/clis/jimeng/generate.yaml +84 -0
- package/src/clis/jimeng/history.yaml +47 -0
- package/src/clis/linux-do/categories.yaml +41 -0
- package/src/clis/linux-do/category.yaml +49 -0
- package/src/clis/linux-do/hot.yaml +50 -0
- package/src/clis/linux-do/latest.yaml +40 -0
- package/src/clis/linux-do/search.yaml +45 -0
- package/src/clis/linux-do/topic.yaml +38 -0
- package/src/clis/notion/README.md +29 -0
- package/src/clis/notion/README.zh-CN.md +29 -0
- package/src/clis/notion/export.ts +36 -0
- package/src/clis/notion/favorites.ts +87 -0
- package/src/clis/notion/new.ts +39 -0
- package/src/clis/notion/read.ts +33 -0
- package/src/clis/notion/search.ts +54 -0
- package/src/clis/notion/sidebar.ts +44 -0
- package/src/clis/notion/status.ts +18 -0
- package/src/clis/notion/write.ts +45 -0
- package/src/clis/twitter/download.ts +227 -0
- package/src/clis/wechat/README.md +28 -0
- package/src/clis/wechat/README.zh-CN.md +28 -0
- package/src/clis/wechat/chats.ts +33 -0
- package/src/clis/wechat/contacts.ts +33 -0
- package/src/clis/wechat/read.ts +72 -0
- package/src/clis/wechat/search.ts +36 -0
- package/src/clis/wechat/send.ts +49 -0
- package/src/clis/wechat/status.ts +35 -0
- package/src/clis/xiaohongshu/creator-note-detail.ts +95 -0
- package/src/clis/xiaohongshu/creator-notes.ts +116 -0
- package/src/clis/xiaohongshu/creator-profile.ts +60 -0
- package/src/clis/xiaohongshu/creator-stats.ts +81 -0
- package/src/clis/xiaohongshu/download.ts +173 -0
- package/src/clis/xiaohongshu/search.ts +1 -1
- package/src/clis/xiaohongshu/user-helpers.test.ts +106 -0
- package/src/clis/xiaohongshu/user-helpers.ts +85 -0
- package/src/clis/xiaohongshu/user.ts +52 -32
- package/src/clis/zhihu/download.test.ts +12 -0
- package/src/clis/zhihu/download.ts +223 -0
- package/src/download/index.ts +395 -0
- package/src/download/progress.ts +125 -0
- package/src/engine.test.ts +17 -0
- package/src/main.ts +12 -3
- package/src/pipeline/registry.ts +2 -0
- package/src/pipeline/steps/download.ts +310 -0
- package/src/pipeline/template.ts +26 -0
- package/tests/e2e/browser-auth.test.ts +25 -0
|
@@ -9,7 +9,7 @@ export const modelCommand = cli({
|
|
|
9
9
|
args: [
|
|
10
10
|
{ name: 'name', help: 'Target model name (e.g. claude, gemini, o1)', required: true, positional: true }
|
|
11
11
|
],
|
|
12
|
-
columns: ['
|
|
12
|
+
columns: ['Status'],
|
|
13
13
|
func: async (page, kwargs) => {
|
|
14
14
|
const targetName = kwargs.name.toLowerCase();
|
|
15
15
|
await page.evaluate(`
|
|
@@ -39,6 +39,6 @@ export const modelCommand = cli({
|
|
|
39
39
|
}
|
|
40
40
|
`);
|
|
41
41
|
await page.wait(0.5);
|
|
42
|
-
return [{
|
|
42
|
+
return [{ Status: `Model switched to: ${kwargs.name}` }];
|
|
43
43
|
},
|
|
44
44
|
});
|
|
@@ -9,7 +9,7 @@ export const sendCommand = cli({
|
|
|
9
9
|
args: [
|
|
10
10
|
{ name: 'message', help: 'The message text to send', required: true, positional: true }
|
|
11
11
|
],
|
|
12
|
-
columns: ['
|
|
12
|
+
columns: ['Status', 'Message'],
|
|
13
13
|
func: async (page, kwargs) => {
|
|
14
14
|
const text = kwargs.message;
|
|
15
15
|
// We use evaluate to focus and insert text because Lexical editors maintain
|
|
@@ -30,6 +30,6 @@ export const sendCommand = cli({
|
|
|
30
30
|
await page.wait(0.5);
|
|
31
31
|
// Press Enter to submit the message
|
|
32
32
|
await page.pressKey('Enter');
|
|
33
|
-
return [{
|
|
33
|
+
return [{ Status: 'Sent successfully', Message: text }];
|
|
34
34
|
},
|
|
35
35
|
});
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bilibili download — download videos using yt-dlp.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* opencli bilibili download --bvid BV1xxx --output ./bilibili
|
|
6
|
+
*
|
|
7
|
+
* Requirements:
|
|
8
|
+
* - yt-dlp must be installed: pip install yt-dlp
|
|
9
|
+
*/
|
|
10
|
+
import * as fs from 'node:fs';
|
|
11
|
+
import * as path from 'node:path';
|
|
12
|
+
import { cli, Strategy } from '../../registry.js';
|
|
13
|
+
import { ytdlpDownload, checkYtdlp, sanitizeFilename, getTempDir, exportCookiesToNetscape, } from '../../download/index.js';
|
|
14
|
+
import { DownloadProgressTracker, formatBytes } from '../../download/progress.js';
|
|
15
|
+
cli({
|
|
16
|
+
site: 'bilibili',
|
|
17
|
+
name: 'download',
|
|
18
|
+
description: '下载B站视频(需要 yt-dlp)',
|
|
19
|
+
domain: 'www.bilibili.com',
|
|
20
|
+
strategy: Strategy.COOKIE,
|
|
21
|
+
args: [
|
|
22
|
+
{ name: 'bvid', required: true, help: 'Video BV ID (e.g., BV1xxx)' },
|
|
23
|
+
{ name: 'output', default: './bilibili-downloads', help: 'Output directory' },
|
|
24
|
+
{ name: 'quality', default: 'best', help: 'Video quality (best, 1080p, 720p, 480p)' },
|
|
25
|
+
],
|
|
26
|
+
columns: ['bvid', 'title', 'status', 'size'],
|
|
27
|
+
func: async (page, kwargs) => {
|
|
28
|
+
const bvid = kwargs.bvid;
|
|
29
|
+
const output = kwargs.output;
|
|
30
|
+
const quality = kwargs.quality;
|
|
31
|
+
// Check yt-dlp availability
|
|
32
|
+
if (!checkYtdlp()) {
|
|
33
|
+
return [{
|
|
34
|
+
bvid,
|
|
35
|
+
title: '-',
|
|
36
|
+
status: 'failed',
|
|
37
|
+
size: 'yt-dlp not installed. Run: pip install yt-dlp',
|
|
38
|
+
}];
|
|
39
|
+
}
|
|
40
|
+
// Navigate to video page to get title and cookies
|
|
41
|
+
await page.goto(`https://www.bilibili.com/video/${bvid}`);
|
|
42
|
+
await page.wait(3);
|
|
43
|
+
// Extract video info
|
|
44
|
+
const data = await page.evaluate(`
|
|
45
|
+
(() => {
|
|
46
|
+
const title = document.querySelector('h1.video-title, .video-title')?.textContent?.trim() || 'video';
|
|
47
|
+
const author = document.querySelector('.up-name, .username')?.textContent?.trim() || 'unknown';
|
|
48
|
+
return { title, author };
|
|
49
|
+
})()
|
|
50
|
+
`);
|
|
51
|
+
const title = sanitizeFilename(data?.title || 'video');
|
|
52
|
+
// Extract cookies for authenticated downloads
|
|
53
|
+
const cookieString = await page.evaluate(`(() => document.cookie)()`);
|
|
54
|
+
// Create output directory
|
|
55
|
+
fs.mkdirSync(output, { recursive: true });
|
|
56
|
+
// Export cookies to Netscape format for yt-dlp
|
|
57
|
+
let cookiesFile;
|
|
58
|
+
if (typeof cookieString === 'string' && cookieString) {
|
|
59
|
+
const tempDir = getTempDir();
|
|
60
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
61
|
+
cookiesFile = path.join(tempDir, `bilibili_cookies_${Date.now()}.txt`);
|
|
62
|
+
const cookies = cookieString.split(';').map((c) => {
|
|
63
|
+
const [name, ...rest] = c.trim().split('=');
|
|
64
|
+
return {
|
|
65
|
+
name: name || '',
|
|
66
|
+
value: rest.join('=') || '',
|
|
67
|
+
domain: '.bilibili.com',
|
|
68
|
+
path: '/',
|
|
69
|
+
secure: true,
|
|
70
|
+
httpOnly: false,
|
|
71
|
+
};
|
|
72
|
+
}).filter((c) => c.name);
|
|
73
|
+
exportCookiesToNetscape(cookies, cookiesFile);
|
|
74
|
+
}
|
|
75
|
+
// Build yt-dlp format string based on quality
|
|
76
|
+
let format = 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best';
|
|
77
|
+
if (quality === '1080p') {
|
|
78
|
+
format = 'bestvideo[height<=1080][ext=mp4]+bestaudio[ext=m4a]/best[height<=1080]';
|
|
79
|
+
}
|
|
80
|
+
else if (quality === '720p') {
|
|
81
|
+
format = 'bestvideo[height<=720][ext=mp4]+bestaudio[ext=m4a]/best[height<=720]';
|
|
82
|
+
}
|
|
83
|
+
else if (quality === '480p') {
|
|
84
|
+
format = 'bestvideo[height<=480][ext=mp4]+bestaudio[ext=m4a]/best[height<=480]';
|
|
85
|
+
}
|
|
86
|
+
const destPath = path.join(output, `${bvid}_${title}.mp4`);
|
|
87
|
+
const tracker = new DownloadProgressTracker(1, true);
|
|
88
|
+
const progressBar = tracker.onFileStart(`${bvid}.mp4`, 0);
|
|
89
|
+
try {
|
|
90
|
+
const result = await ytdlpDownload(`https://www.bilibili.com/video/${bvid}`, destPath, {
|
|
91
|
+
cookiesFile,
|
|
92
|
+
format,
|
|
93
|
+
extraArgs: [
|
|
94
|
+
'--merge-output-format', 'mp4',
|
|
95
|
+
'--embed-thumbnail',
|
|
96
|
+
],
|
|
97
|
+
onProgress: (percent) => {
|
|
98
|
+
if (progressBar)
|
|
99
|
+
progressBar.update(percent, 100);
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
if (progressBar) {
|
|
103
|
+
progressBar.complete(result.success, result.success ? formatBytes(result.size) : undefined);
|
|
104
|
+
}
|
|
105
|
+
tracker.onFileComplete(result.success);
|
|
106
|
+
tracker.finish();
|
|
107
|
+
// Cleanup cookies file
|
|
108
|
+
if (cookiesFile && fs.existsSync(cookiesFile)) {
|
|
109
|
+
fs.unlinkSync(cookiesFile);
|
|
110
|
+
}
|
|
111
|
+
return [{
|
|
112
|
+
bvid,
|
|
113
|
+
title: data?.title || 'video',
|
|
114
|
+
status: result.success ? 'success' : 'failed',
|
|
115
|
+
size: result.success ? formatBytes(result.size) : (result.error || 'unknown error'),
|
|
116
|
+
}];
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
if (progressBar)
|
|
120
|
+
progressBar.fail(err.message);
|
|
121
|
+
tracker.onFileComplete(false);
|
|
122
|
+
tracker.finish();
|
|
123
|
+
// Cleanup cookies file
|
|
124
|
+
if (cookiesFile && fs.existsSync(cookiesFile)) {
|
|
125
|
+
fs.unlinkSync(cookiesFile);
|
|
126
|
+
}
|
|
127
|
+
return [{
|
|
128
|
+
bvid,
|
|
129
|
+
title: data?.title || 'video',
|
|
130
|
+
status: 'failed',
|
|
131
|
+
size: err.message,
|
|
132
|
+
}];
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const askCommand: import("../../registry.js").CliCommand;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { execSync, spawnSync } from 'node:child_process';
|
|
2
|
+
import { cli, Strategy } from '../../registry.js';
|
|
3
|
+
export const askCommand = cli({
|
|
4
|
+
site: 'chatgpt',
|
|
5
|
+
name: 'ask',
|
|
6
|
+
description: 'Send a prompt and wait for the AI response (send + wait + read)',
|
|
7
|
+
domain: 'localhost',
|
|
8
|
+
strategy: Strategy.PUBLIC,
|
|
9
|
+
browser: false,
|
|
10
|
+
args: [
|
|
11
|
+
{ name: 'text', required: true, positional: true, help: 'Prompt to send' },
|
|
12
|
+
{ name: 'timeout', required: false, help: 'Max seconds to wait for response (default: 30)', default: '30' },
|
|
13
|
+
],
|
|
14
|
+
columns: ['Role', 'Text'],
|
|
15
|
+
func: async (page, kwargs) => {
|
|
16
|
+
const text = kwargs.text;
|
|
17
|
+
const timeout = parseInt(kwargs.timeout, 10) || 30;
|
|
18
|
+
// Backup clipboard
|
|
19
|
+
let clipBackup = '';
|
|
20
|
+
try {
|
|
21
|
+
clipBackup = execSync('pbpaste', { encoding: 'utf-8' });
|
|
22
|
+
}
|
|
23
|
+
catch { }
|
|
24
|
+
// Send the message
|
|
25
|
+
spawnSync('pbcopy', { input: text });
|
|
26
|
+
execSync("osascript -e 'tell application \"ChatGPT\" to activate'");
|
|
27
|
+
execSync("osascript -e 'delay 0.5'");
|
|
28
|
+
const cmd = "osascript " +
|
|
29
|
+
"-e 'tell application \"System Events\"' " +
|
|
30
|
+
"-e 'keystroke \"v\" using command down' " +
|
|
31
|
+
"-e 'delay 0.2' " +
|
|
32
|
+
"-e 'keystroke return' " +
|
|
33
|
+
"-e 'end tell'";
|
|
34
|
+
execSync(cmd);
|
|
35
|
+
// Clear clipboard marker
|
|
36
|
+
spawnSync('pbcopy', { input: '__OPENCLI_WAITING__' });
|
|
37
|
+
// Wait for response, then read it
|
|
38
|
+
const pollInterval = 3;
|
|
39
|
+
const maxPolls = Math.ceil(timeout / pollInterval);
|
|
40
|
+
let response = '';
|
|
41
|
+
for (let i = 0; i < maxPolls; i++) {
|
|
42
|
+
// Wait
|
|
43
|
+
execSync(`sleep ${pollInterval}`);
|
|
44
|
+
// Try Cmd+Shift+C to copy the latest response
|
|
45
|
+
execSync("osascript -e 'tell application \"ChatGPT\" to activate'");
|
|
46
|
+
execSync("osascript -e 'tell application \"System Events\" to keystroke \"c\" using {command down, shift down}'");
|
|
47
|
+
execSync("osascript -e 'delay 0.3'");
|
|
48
|
+
const copied = execSync('pbpaste', { encoding: 'utf-8' }).trim();
|
|
49
|
+
if (copied && copied !== '__OPENCLI_WAITING__' && copied !== text) {
|
|
50
|
+
response = copied;
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Restore clipboard
|
|
55
|
+
if (clipBackup)
|
|
56
|
+
spawnSync('pbcopy', { input: clipBackup });
|
|
57
|
+
if (!response) {
|
|
58
|
+
return [
|
|
59
|
+
{ Role: 'User', Text: text },
|
|
60
|
+
{ Role: 'System', Text: `No response within ${timeout}s. ChatGPT may still be generating.` },
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
return [
|
|
64
|
+
{ Role: 'User', Text: text },
|
|
65
|
+
{ Role: 'Assistant', Text: response },
|
|
66
|
+
];
|
|
67
|
+
},
|
|
68
|
+
});
|
|
@@ -12,6 +12,13 @@ export const sendCommand = cli({
|
|
|
12
12
|
func: async (page, kwargs) => {
|
|
13
13
|
const text = kwargs.text;
|
|
14
14
|
try {
|
|
15
|
+
// Backup current clipboard content
|
|
16
|
+
let clipBackup = '';
|
|
17
|
+
try {
|
|
18
|
+
clipBackup = execSync('pbpaste', { encoding: 'utf-8' });
|
|
19
|
+
}
|
|
20
|
+
catch { /* clipboard may be empty */ }
|
|
21
|
+
// Copy text to clipboard
|
|
15
22
|
spawnSync('pbcopy', { input: text });
|
|
16
23
|
execSync("osascript -e 'tell application \"ChatGPT\" to activate'");
|
|
17
24
|
execSync("osascript -e 'delay 0.5'");
|
|
@@ -22,6 +29,10 @@ export const sendCommand = cli({
|
|
|
22
29
|
"-e 'keystroke return' " +
|
|
23
30
|
"-e 'end tell'";
|
|
24
31
|
execSync(cmd);
|
|
32
|
+
// Restore original clipboard content
|
|
33
|
+
if (clipBackup) {
|
|
34
|
+
spawnSync('pbcopy', { input: clipBackup });
|
|
35
|
+
}
|
|
25
36
|
return [{ Status: 'Success' }];
|
|
26
37
|
}
|
|
27
38
|
catch (err) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const askCommand: import("../../registry.js").CliCommand;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { cli, Strategy } from '../../registry.js';
|
|
2
|
+
export const askCommand = cli({
|
|
3
|
+
site: 'chatwise',
|
|
4
|
+
name: 'ask',
|
|
5
|
+
description: 'Send a prompt and wait for the AI response (send + wait + read)',
|
|
6
|
+
domain: 'localhost',
|
|
7
|
+
strategy: Strategy.UI,
|
|
8
|
+
browser: true,
|
|
9
|
+
args: [
|
|
10
|
+
{ name: 'text', required: true, positional: true, help: 'Prompt to send' },
|
|
11
|
+
{ name: 'timeout', required: false, help: 'Max seconds to wait (default: 30)', default: '30' },
|
|
12
|
+
],
|
|
13
|
+
columns: ['Role', 'Text'],
|
|
14
|
+
func: async (page, kwargs) => {
|
|
15
|
+
const text = kwargs.text;
|
|
16
|
+
const timeout = parseInt(kwargs.timeout, 10) || 30;
|
|
17
|
+
// Snapshot content length
|
|
18
|
+
const beforeLen = await page.evaluate(`
|
|
19
|
+
(function() {
|
|
20
|
+
const msgs = document.querySelectorAll('[data-message-id], [class*="message"], [class*="bubble"]');
|
|
21
|
+
return msgs.length;
|
|
22
|
+
})()
|
|
23
|
+
`);
|
|
24
|
+
// Send message
|
|
25
|
+
await page.evaluate(`
|
|
26
|
+
(function(text) {
|
|
27
|
+
let composer = document.querySelector('textarea');
|
|
28
|
+
if (!composer) {
|
|
29
|
+
const editables = Array.from(document.querySelectorAll('[contenteditable="true"]'));
|
|
30
|
+
composer = editables.length > 0 ? editables[editables.length - 1] : null;
|
|
31
|
+
}
|
|
32
|
+
if (!composer) throw new Error('Could not find input');
|
|
33
|
+
composer.focus();
|
|
34
|
+
if (composer.tagName === 'TEXTAREA') {
|
|
35
|
+
const setter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value').set;
|
|
36
|
+
setter.call(composer, text);
|
|
37
|
+
composer.dispatchEvent(new Event('input', { bubbles: true }));
|
|
38
|
+
} else {
|
|
39
|
+
document.execCommand('insertText', false, text);
|
|
40
|
+
}
|
|
41
|
+
})(${JSON.stringify(text)})
|
|
42
|
+
`);
|
|
43
|
+
await page.wait(0.5);
|
|
44
|
+
await page.pressKey('Enter');
|
|
45
|
+
// Poll for response
|
|
46
|
+
const pollInterval = 2;
|
|
47
|
+
const maxPolls = Math.ceil(timeout / pollInterval);
|
|
48
|
+
let response = '';
|
|
49
|
+
for (let i = 0; i < maxPolls; i++) {
|
|
50
|
+
await page.wait(pollInterval);
|
|
51
|
+
const result = await page.evaluate(`
|
|
52
|
+
(function(prevLen) {
|
|
53
|
+
const msgs = document.querySelectorAll('[data-message-id], [class*="message"], [class*="bubble"]');
|
|
54
|
+
if (msgs.length <= prevLen) return null;
|
|
55
|
+
const last = msgs[msgs.length - 1];
|
|
56
|
+
const text = last.innerText || last.textContent;
|
|
57
|
+
return text ? text.trim() : null;
|
|
58
|
+
})(${beforeLen})
|
|
59
|
+
`);
|
|
60
|
+
if (result) {
|
|
61
|
+
response = result;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (!response) {
|
|
66
|
+
return [
|
|
67
|
+
{ Role: 'User', Text: text },
|
|
68
|
+
{ Role: 'System', Text: `No response within ${timeout}s.` },
|
|
69
|
+
];
|
|
70
|
+
}
|
|
71
|
+
return [
|
|
72
|
+
{ Role: 'User', Text: text },
|
|
73
|
+
{ Role: 'Assistant', Text: response },
|
|
74
|
+
];
|
|
75
|
+
},
|
|
76
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const exportCommand: import("../../registry.js").CliCommand;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import { cli, Strategy } from '../../registry.js';
|
|
3
|
+
export const exportCommand = cli({
|
|
4
|
+
site: 'chatwise',
|
|
5
|
+
name: 'export',
|
|
6
|
+
description: 'Export the current ChatWise conversation to a Markdown file',
|
|
7
|
+
domain: 'localhost',
|
|
8
|
+
strategy: Strategy.UI,
|
|
9
|
+
browser: true,
|
|
10
|
+
args: [
|
|
11
|
+
{ name: 'output', required: false, positional: true, help: 'Output file (default: /tmp/chatwise-export.md)' },
|
|
12
|
+
],
|
|
13
|
+
columns: ['Status', 'File', 'Messages'],
|
|
14
|
+
func: async (page, kwargs) => {
|
|
15
|
+
const outputPath = kwargs.output || '/tmp/chatwise-export.md';
|
|
16
|
+
const md = await page.evaluate(`
|
|
17
|
+
(function() {
|
|
18
|
+
const selectors = [
|
|
19
|
+
'[data-message-id]',
|
|
20
|
+
'[class*="message"]',
|
|
21
|
+
'[class*="chat-item"]',
|
|
22
|
+
'[class*="bubble"]',
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
for (const sel of selectors) {
|
|
26
|
+
const nodes = document.querySelectorAll(sel);
|
|
27
|
+
if (nodes.length > 0) {
|
|
28
|
+
return Array.from(nodes).map((n, i) => '## Message ' + (i + 1) + '\\n\\n' + (n.innerText || n.textContent).trim()).join('\\n\\n---\\n\\n');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const main = document.querySelector('main, [role="main"], [class*="chat-container"]');
|
|
33
|
+
if (main) return main.innerText || main.textContent;
|
|
34
|
+
return document.body.innerText;
|
|
35
|
+
})()
|
|
36
|
+
`);
|
|
37
|
+
fs.writeFileSync(outputPath, '# ChatWise Conversation Export\\n\\n' + md);
|
|
38
|
+
return [
|
|
39
|
+
{
|
|
40
|
+
Status: 'Success',
|
|
41
|
+
File: outputPath,
|
|
42
|
+
Messages: md.split('## Message').length - 1,
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
},
|
|
46
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const historyCommand: import("../../registry.js").CliCommand;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { cli, Strategy } from '../../registry.js';
|
|
2
|
+
export const historyCommand = cli({
|
|
3
|
+
site: 'chatwise',
|
|
4
|
+
name: 'history',
|
|
5
|
+
description: 'List conversation history in ChatWise sidebar',
|
|
6
|
+
domain: 'localhost',
|
|
7
|
+
strategy: Strategy.UI,
|
|
8
|
+
browser: true,
|
|
9
|
+
args: [],
|
|
10
|
+
columns: ['Index', 'Title'],
|
|
11
|
+
func: async (page) => {
|
|
12
|
+
const items = await page.evaluate(`
|
|
13
|
+
(function() {
|
|
14
|
+
const results = [];
|
|
15
|
+
const selectors = [
|
|
16
|
+
'[class*="sidebar"] [class*="item"]',
|
|
17
|
+
'[class*="conversation-list"] a',
|
|
18
|
+
'[class*="chat-list"] > *',
|
|
19
|
+
'nav a',
|
|
20
|
+
'aside a',
|
|
21
|
+
'[role="listbox"] [role="option"]',
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
for (const sel of selectors) {
|
|
25
|
+
const nodes = document.querySelectorAll(sel);
|
|
26
|
+
if (nodes.length > 0) {
|
|
27
|
+
nodes.forEach((n, i) => {
|
|
28
|
+
const text = (n.textContent || '').trim().substring(0, 100);
|
|
29
|
+
if (text) results.push({ Index: i + 1, Title: text });
|
|
30
|
+
});
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return results;
|
|
36
|
+
})()
|
|
37
|
+
`);
|
|
38
|
+
if (items.length === 0) {
|
|
39
|
+
return [{ Index: 0, Title: 'No history found. Ensure the sidebar is visible.' }];
|
|
40
|
+
}
|
|
41
|
+
return items;
|
|
42
|
+
},
|
|
43
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const modelCommand: import("../../registry.js").CliCommand;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { cli, Strategy } from '../../registry.js';
|
|
2
|
+
export const modelCommand = cli({
|
|
3
|
+
site: 'chatwise',
|
|
4
|
+
name: 'model',
|
|
5
|
+
description: 'Get or switch the active AI model in ChatWise',
|
|
6
|
+
domain: 'localhost',
|
|
7
|
+
strategy: Strategy.UI,
|
|
8
|
+
browser: true,
|
|
9
|
+
args: [
|
|
10
|
+
{ name: 'model_name', required: false, positional: true, help: 'Model to switch to (e.g. gpt-4, claude-3)' },
|
|
11
|
+
],
|
|
12
|
+
columns: ['Status', 'Model'],
|
|
13
|
+
func: async (page, kwargs) => {
|
|
14
|
+
const desiredModel = kwargs.model_name;
|
|
15
|
+
if (!desiredModel) {
|
|
16
|
+
// Read current model
|
|
17
|
+
const currentModel = await page.evaluate(`
|
|
18
|
+
(function() {
|
|
19
|
+
// ChatWise is a multi-LLM client, it typically shows the model name in a dropdown or header
|
|
20
|
+
const selectors = [
|
|
21
|
+
'[class*="model"] span',
|
|
22
|
+
'[class*="Model"] span',
|
|
23
|
+
'[data-testid*="model"]',
|
|
24
|
+
'button[class*="model"]',
|
|
25
|
+
'[aria-label*="Model"]',
|
|
26
|
+
'[aria-label*="model"]',
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
for (const sel of selectors) {
|
|
30
|
+
const el = document.querySelector(sel);
|
|
31
|
+
if (el) {
|
|
32
|
+
const text = (el.textContent || el.getAttribute('title') || '').trim();
|
|
33
|
+
if (text) return text;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return 'Unknown or Not Found';
|
|
38
|
+
})()
|
|
39
|
+
`);
|
|
40
|
+
return [{ Status: 'Active', Model: currentModel }];
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
// Try to switch model
|
|
44
|
+
await page.evaluate(`
|
|
45
|
+
(function(target) {
|
|
46
|
+
const selectors = [
|
|
47
|
+
'[class*="model"]',
|
|
48
|
+
'[class*="Model"]',
|
|
49
|
+
'button[class*="model"]',
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
for (const sel of selectors) {
|
|
53
|
+
const el = document.querySelector(sel);
|
|
54
|
+
if (el) { el.click(); return; }
|
|
55
|
+
}
|
|
56
|
+
throw new Error('Could not find model selector');
|
|
57
|
+
})(${JSON.stringify(desiredModel)})
|
|
58
|
+
`);
|
|
59
|
+
await page.wait(0.5);
|
|
60
|
+
// Find and click the target model in the dropdown
|
|
61
|
+
const found = await page.evaluate(`
|
|
62
|
+
(function(target) {
|
|
63
|
+
const options = document.querySelectorAll('[role="option"], [role="menuitem"], [class*="dropdown-item"], li');
|
|
64
|
+
for (const opt of options) {
|
|
65
|
+
if ((opt.textContent || '').toLowerCase().includes(target.toLowerCase())) {
|
|
66
|
+
opt.click();
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
})(${JSON.stringify(desiredModel)})
|
|
72
|
+
`);
|
|
73
|
+
return [
|
|
74
|
+
{
|
|
75
|
+
Status: found ? 'Switched' : 'Dropdown opened but model not found',
|
|
76
|
+
Model: desiredModel,
|
|
77
|
+
},
|
|
78
|
+
];
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const newCommand: import("../../registry.js").CliCommand;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { cli, Strategy } from '../../registry.js';
|
|
2
|
+
export const newCommand = cli({
|
|
3
|
+
site: 'chatwise',
|
|
4
|
+
name: 'new',
|
|
5
|
+
description: 'Start a new conversation in ChatWise',
|
|
6
|
+
domain: 'localhost',
|
|
7
|
+
strategy: Strategy.UI,
|
|
8
|
+
browser: true,
|
|
9
|
+
args: [],
|
|
10
|
+
columns: ['Status'],
|
|
11
|
+
func: async (page) => {
|
|
12
|
+
// ChatWise uses standard Electron shortcuts
|
|
13
|
+
const isMac = process.platform === 'darwin';
|
|
14
|
+
await page.pressKey(isMac ? 'Meta+N' : 'Control+N');
|
|
15
|
+
await page.wait(1);
|
|
16
|
+
return [{ Status: 'Success' }];
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const readCommand: import("../../registry.js").CliCommand;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { cli, Strategy } from '../../registry.js';
|
|
2
|
+
export const readCommand = cli({
|
|
3
|
+
site: 'chatwise',
|
|
4
|
+
name: 'read',
|
|
5
|
+
description: 'Read the current ChatWise conversation history',
|
|
6
|
+
domain: 'localhost',
|
|
7
|
+
strategy: Strategy.UI,
|
|
8
|
+
browser: true,
|
|
9
|
+
args: [],
|
|
10
|
+
columns: ['Content'],
|
|
11
|
+
func: async (page) => {
|
|
12
|
+
const content = await page.evaluate(`
|
|
13
|
+
(function() {
|
|
14
|
+
// Try common chat message selectors
|
|
15
|
+
const selectors = [
|
|
16
|
+
'[data-message-id]',
|
|
17
|
+
'[class*="message"]',
|
|
18
|
+
'[class*="chat-item"]',
|
|
19
|
+
'[class*="bubble"]',
|
|
20
|
+
'[role="log"] > *',
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
for (const sel of selectors) {
|
|
24
|
+
const nodes = document.querySelectorAll(sel);
|
|
25
|
+
if (nodes.length > 0) {
|
|
26
|
+
return Array.from(nodes).map(n => (n.innerText || n.textContent).trim()).filter(Boolean).join('\\n\\n---\\n\\n');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Fallback: main content area
|
|
31
|
+
const main = document.querySelector('main, [role="main"], [class*="chat-container"], [class*="conversation"]');
|
|
32
|
+
if (main) return main.innerText || main.textContent;
|
|
33
|
+
|
|
34
|
+
return document.body.innerText;
|
|
35
|
+
})()
|
|
36
|
+
`);
|
|
37
|
+
return [{ Content: content }];
|
|
38
|
+
},
|
|
39
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const screenshotCommand: import("../../registry.js").CliCommand;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import { cli, Strategy } from '../../registry.js';
|
|
3
|
+
export const screenshotCommand = cli({
|
|
4
|
+
site: 'chatwise',
|
|
5
|
+
name: 'screenshot',
|
|
6
|
+
description: 'Capture a snapshot of the current ChatWise window (DOM + Accessibility tree)',
|
|
7
|
+
domain: 'localhost',
|
|
8
|
+
strategy: Strategy.UI,
|
|
9
|
+
browser: true,
|
|
10
|
+
args: [
|
|
11
|
+
{ name: 'output', required: false, positional: true, help: 'Output file path (default: /tmp/chatwise-snapshot)' },
|
|
12
|
+
],
|
|
13
|
+
columns: ['Status', 'File'],
|
|
14
|
+
func: async (page, kwargs) => {
|
|
15
|
+
const basePath = kwargs.output || '/tmp/chatwise-snapshot';
|
|
16
|
+
const snap = await page.snapshot({ compact: true });
|
|
17
|
+
const html = await page.evaluate('document.documentElement.outerHTML');
|
|
18
|
+
const htmlPath = basePath + '-dom.html';
|
|
19
|
+
const snapPath = basePath + '-a11y.txt';
|
|
20
|
+
fs.writeFileSync(htmlPath, html);
|
|
21
|
+
fs.writeFileSync(snapPath, typeof snap === 'string' ? snap : JSON.stringify(snap, null, 2));
|
|
22
|
+
return [
|
|
23
|
+
{ Status: 'Success', File: htmlPath },
|
|
24
|
+
{ Status: 'Success', File: snapPath },
|
|
25
|
+
];
|
|
26
|
+
},
|
|
27
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const sendCommand: import("../../registry.js").CliCommand;
|