@jackwener/opencli 1.7.12 → 1.7.13
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 +8 -7
- package/README.zh-CN.md +9 -8
- package/cli-manifest.json +12194 -6843
- package/clis/1point3acres/digest.js +35 -0
- package/clis/1point3acres/forum.js +51 -0
- package/clis/1point3acres/forums.js +44 -0
- package/clis/1point3acres/hot.js +35 -0
- package/clis/1point3acres/latest.js +35 -0
- package/clis/1point3acres/notifications.js +64 -0
- package/clis/1point3acres/search.js +71 -0
- package/clis/1point3acres/thread.js +117 -0
- package/clis/1point3acres/user.js +77 -0
- package/clis/1point3acres/utils.js +247 -0
- package/clis/_shared/desktop-commands.js +4 -0
- package/clis/aibase/news.js +110 -0
- package/clis/aibase/news.test.js +59 -0
- package/clis/amazon/discussion.test.js +1 -28
- package/clis/antigravity/watch.js +3 -2
- package/clis/arxiv/author.js +44 -0
- package/clis/baidu-scholar/search.js +0 -1
- package/clis/bbc/topic.js +57 -0
- package/clis/bbc/utils.js +79 -0
- package/clis/chaoxing/assignments.js +1 -1
- package/clis/chaoxing/exams.js +1 -1
- package/clis/chatgpt/ask.js +57 -0
- package/clis/chatgpt/commands.test.js +45 -0
- package/clis/chatgpt/detail.js +46 -0
- package/clis/chatgpt/history.js +39 -0
- package/clis/chatgpt/image.js +12 -11
- package/clis/chatgpt/image.test.js +23 -0
- package/clis/chatgpt/new.js +25 -0
- package/clis/chatgpt/read.js +43 -0
- package/clis/chatgpt/send.js +46 -0
- package/clis/chatgpt/status.js +29 -0
- package/clis/chatgpt/utils.js +294 -4
- package/clis/chatgpt/utils.test.js +13 -0
- package/clis/chatgpt-app/ask.js +6 -3
- package/clis/chatwise/ask.js +16 -43
- package/clis/chatwise/composer.test.js +186 -0
- package/clis/chatwise/send.js +2 -24
- package/clis/chatwise/utils.js +143 -0
- package/clis/claude/ask.js +1 -1
- package/clis/claude/detail.js +1 -0
- package/clis/claude/history.js +1 -0
- package/clis/claude/new.js +1 -0
- package/clis/claude/read.js +1 -0
- package/clis/claude/send.js +1 -0
- package/clis/claude/status.js +1 -0
- package/clis/codex/ask.js +15 -9
- package/clis/codex/history.js +16 -33
- package/clis/codex/projects.js +28 -0
- package/clis/codex/read.js +10 -4
- package/clis/codex/send.js +10 -3
- package/clis/codex/sidebar.js +356 -0
- package/clis/codex/sidebar.test.js +329 -0
- package/clis/coingecko/categories.js +75 -0
- package/clis/coingecko/coin.js +107 -0
- package/clis/coingecko/coingecko.test.js +109 -0
- package/clis/coingecko/derivatives.js +84 -0
- package/clis/coingecko/exchanges.js +74 -0
- package/clis/coingecko/global.js +71 -0
- package/clis/coingecko/top.js +64 -0
- package/clis/coingecko/trending.js +55 -0
- package/clis/coupang/add-to-cart.js +21 -13
- package/clis/coupang/coupang.test.js +159 -0
- package/clis/coupang/product.js +257 -0
- package/clis/coupang/search.js +38 -16
- package/clis/coupang/utils.js +55 -1
- package/clis/crates/crate.js +62 -0
- package/clis/crates/search.js +44 -0
- package/clis/crates/utils.js +72 -0
- package/clis/ctrip/ctrip.test.js +234 -0
- package/clis/ctrip/hotel-suggest.js +45 -0
- package/clis/ctrip/search.js +22 -68
- package/clis/ctrip/utils.js +175 -0
- package/clis/cursor/ask.js +6 -3
- package/clis/dblp/author.js +133 -0
- package/clis/dblp/venue.js +64 -0
- package/clis/deepseek/ask.js +12 -7
- package/clis/deepseek/ask.test.js +13 -13
- package/clis/deepseek/detail.js +38 -0
- package/clis/deepseek/detail.test.js +81 -0
- package/clis/deepseek/history.js +1 -0
- package/clis/deepseek/new.js +1 -0
- package/clis/deepseek/read.js +1 -0
- package/clis/deepseek/send.js +140 -0
- package/clis/deepseek/send.test.js +107 -0
- package/clis/deepseek/status.js +1 -0
- package/clis/deepseek/utils.js +66 -0
- package/clis/deepseek/utils.test.js +107 -1
- package/clis/defillama/defillama.test.js +99 -0
- package/clis/defillama/protocol.js +84 -0
- package/clis/defillama/protocols.js +55 -0
- package/clis/defillama/utils.js +99 -0
- package/clis/devto/latest.js +74 -0
- package/clis/dockerhub/image.js +52 -0
- package/clis/dockerhub/search.js +47 -0
- package/clis/dockerhub/utils.js +100 -0
- package/clis/doubao/ask.js +7 -3
- package/clis/doubao/detail.js +1 -0
- package/clis/doubao/history.js +1 -0
- package/clis/doubao/meeting-summary.js +1 -0
- package/clis/doubao/meeting-transcript.js +1 -0
- package/clis/doubao/new.js +1 -0
- package/clis/doubao/read.js +1 -0
- package/clis/doubao/send.js +1 -0
- package/clis/doubao/status.js +1 -0
- package/clis/douyin/draft.test.js +1 -30
- package/clis/endoflife/endoflife.test.js +51 -0
- package/clis/endoflife/product.js +55 -0
- package/clis/endoflife/utils.js +89 -0
- package/clis/facebook/__fixtures__/notifications-page.html +13 -0
- package/clis/facebook/notifications.js +326 -30
- package/clis/facebook/notifications.test.js +458 -0
- package/clis/flathub/app.js +71 -0
- package/clis/flathub/flathub.test.js +90 -0
- package/clis/flathub/search.js +80 -0
- package/clis/flathub/utils.js +114 -0
- package/clis/gemini/ask.js +7 -3
- package/clis/gemini/ask.test.js +2 -2
- package/clis/gemini/deep-research-result.js +6 -2
- package/clis/gemini/deep-research-result.test.js +15 -14
- package/clis/gemini/deep-research.js +8 -4
- package/clis/gemini/deep-research.test.js +15 -18
- package/clis/gemini/image.js +7 -2
- package/clis/gemini/new.js +1 -0
- package/clis/gemini/utils.js +0 -4
- package/clis/google-scholar/cite.js +0 -1
- package/clis/google-scholar/profile.js +0 -1
- package/clis/google-scholar/search.js +0 -1
- package/clis/goproxy/goproxy.test.js +103 -0
- package/clis/goproxy/module.js +47 -0
- package/clis/goproxy/utils.js +165 -0
- package/clis/goproxy/versions.js +59 -0
- package/clis/gov-law/recent.js +0 -1
- package/clis/gov-law/search.js +0 -1
- package/clis/gov-policy/__fixtures__/recent.html +16 -0
- package/clis/gov-policy/__fixtures__/search.html +41 -0
- package/clis/gov-policy/gov-policy.test.js +224 -0
- package/clis/gov-policy/recent.js +66 -24
- package/clis/gov-policy/search.js +65 -23
- package/clis/gov-policy/utils.js +54 -0
- package/clis/grok/ask.js +49 -265
- package/clis/grok/ask.test.js +21 -46
- package/clis/grok/detail.js +60 -0
- package/clis/grok/history.js +48 -0
- package/clis/grok/{image.ts → image.js} +56 -70
- package/clis/grok/image.test.ts +20 -0
- package/clis/grok/new.js +20 -0
- package/clis/grok/read.js +39 -0
- package/clis/grok/send.js +50 -0
- package/clis/grok/status.js +41 -0
- package/clis/grok/utils.js +326 -0
- package/clis/grok/utils.test.js +103 -0
- package/clis/hf/datasets.js +88 -0
- package/clis/hf/hf.test.js +16 -0
- package/clis/hf/models.js +91 -0
- package/clis/hf/paper.js +79 -0
- package/clis/hf/spaces.js +101 -0
- package/clis/hf/top.js +1 -0
- package/clis/homebrew/cask.js +39 -0
- package/clis/homebrew/formula.js +41 -0
- package/clis/homebrew/popular.js +54 -0
- package/clis/homebrew/utils.js +100 -0
- package/clis/hupu/__fixtures__/hot-home.html +64 -0
- package/clis/hupu/detail.js +0 -1
- package/clis/hupu/hot.js +156 -35
- package/clis/hupu/hot.test.js +224 -0
- package/clis/hupu/search.js +0 -1
- package/clis/instagram/note.js +1 -1
- package/clis/instagram/note.test.js +1 -29
- package/clis/instagram/post.js +1 -1
- package/clis/instagram/post.test.js +1 -1
- package/clis/instagram/reel.js +1 -1
- package/clis/instagram/story.js +1 -1
- package/clis/instagram/story.test.js +1 -34
- package/clis/jd/commands.test.js +1 -24
- package/clis/lichess/lichess.test.js +85 -0
- package/clis/lichess/top.js +46 -0
- package/clis/lichess/user.js +91 -0
- package/clis/lichess/utils.js +97 -0
- package/clis/linkedin/search.js +107 -10
- package/clis/linkedin/search.test.js +222 -0
- package/clis/linux-do/feed.js +2 -5
- package/clis/linux-do/feed.test.js +35 -0
- package/clis/lobsters/domain.js +92 -0
- package/clis/maven/artifact.js +49 -0
- package/clis/maven/search.js +51 -0
- package/clis/maven/utils.js +110 -0
- package/clis/mdn/search.js +97 -0
- package/clis/medium/tag.js +135 -0
- package/clis/npm/downloads.js +59 -0
- package/clis/npm/package.js +70 -0
- package/clis/npm/search.js +49 -0
- package/clis/npm/utils.js +76 -0
- package/clis/nuget/nuget.test.js +111 -0
- package/clis/nuget/package.js +101 -0
- package/clis/nuget/search.js +69 -0
- package/clis/nuget/utils.js +87 -0
- package/clis/nvd/cve.js +121 -0
- package/clis/oeis/oeis.test.js +88 -0
- package/clis/oeis/search.js +63 -0
- package/clis/oeis/sequence.js +71 -0
- package/clis/oeis/utils.js +88 -0
- package/clis/openalex/search.js +69 -0
- package/clis/openalex/utils.js +160 -0
- package/clis/openalex/work.js +65 -0
- package/clis/openfda/drug-label.js +74 -0
- package/clis/openfda/food-recall.js +65 -0
- package/clis/openfda/openfda.test.js +114 -0
- package/clis/openfda/utils.js +67 -0
- package/clis/osv/osv.test.js +97 -0
- package/clis/osv/query.js +72 -0
- package/clis/osv/utils.js +169 -0
- package/clis/osv/vulnerability.js +54 -0
- package/clis/packagist/package.js +49 -0
- package/clis/packagist/search.js +43 -0
- package/clis/packagist/utils.js +113 -0
- package/clis/paperreview/feedback.js +1 -1
- package/clis/paperreview/review.js +1 -1
- package/clis/paperreview/submit.js +1 -1
- package/clis/pixiv/download.test.js +1 -1
- package/clis/pixiv/illusts.test.js +1 -1
- package/clis/pixiv/search.test.js +1 -1
- package/clis/pubmed/article.js +50 -0
- package/clis/pubmed/author.js +64 -0
- package/clis/pubmed/citations.js +36 -0
- package/clis/pubmed/pubmed.test.js +276 -0
- package/clis/pubmed/related.js +45 -0
- package/clis/pubmed/search.js +75 -0
- package/clis/pubmed/utils.js +309 -0
- package/clis/pypi/downloads.js +66 -0
- package/clis/pypi/package.js +79 -0
- package/clis/pypi/utils.js +55 -0
- package/clis/quark/mv.js +1 -1
- package/clis/quark/save.js +1 -1
- package/clis/qwen/ask.js +85 -0
- package/clis/qwen/detail.js +62 -0
- package/clis/qwen/history.js +61 -0
- package/clis/qwen/image.js +179 -0
- package/clis/qwen/new.js +23 -0
- package/clis/qwen/read.js +41 -0
- package/clis/qwen/send.js +55 -0
- package/clis/qwen/status.js +37 -0
- package/clis/qwen/utils.js +409 -0
- package/clis/qwen/utils.test.js +45 -0
- package/clis/rest-countries/country.js +65 -0
- package/clis/rest-countries/region.js +64 -0
- package/clis/rest-countries/rest-countries.test.js +83 -0
- package/clis/rest-countries/utils.js +126 -0
- package/clis/reuters/article-detail.js +53 -0
- package/clis/reuters/reuters.test.js +299 -0
- package/clis/reuters/search.js +45 -34
- package/clis/reuters/utils.js +159 -0
- package/clis/rfc/rfc.js +52 -0
- package/clis/rfc/rfc.test.js +74 -0
- package/clis/rfc/utils.js +72 -0
- package/clis/rubygems/gem.js +42 -0
- package/clis/rubygems/search.js +47 -0
- package/clis/rubygems/utils.js +86 -0
- package/clis/stackoverflow/related.js +66 -0
- package/clis/stackoverflow/stackoverflow.test.js +58 -0
- package/clis/stackoverflow/tag.js +60 -0
- package/clis/stackoverflow/user.js +50 -0
- package/clis/stackoverflow/utils.js +118 -0
- package/clis/steam/app.js +67 -0
- package/clis/steam/search.js +58 -0
- package/clis/steam/steam.test.js +46 -0
- package/clis/steam/utils.js +107 -0
- package/clis/taobao/commands.test.js +1 -24
- package/clis/test-utils.js +61 -0
- package/clis/tieba/hot.js +0 -1
- package/clis/tiktok/comment.js +128 -41
- package/clis/tiktok/creator-videos.js +270 -0
- package/clis/tiktok/creator-videos.test.js +113 -0
- package/clis/tiktok/explore.js +137 -29
- package/clis/tiktok/follow.js +115 -33
- package/clis/tiktok/following.js +157 -36
- package/clis/tiktok/friends.js +139 -37
- package/clis/tiktok/live.js +137 -41
- package/clis/tiktok/notifications.js +141 -38
- package/clis/tiktok/refactor.test.js +389 -0
- package/clis/tiktok/unfollow.js +124 -38
- package/clis/tiktok/user.js +203 -29
- package/clis/tiktok/utils.js +505 -0
- package/clis/tiktok/write-refactor.test.js +370 -0
- package/clis/toutiao/articles.js +36 -62
- package/clis/toutiao/hot.js +63 -0
- package/clis/toutiao/toutiao.test.js +378 -0
- package/clis/toutiao/utils.js +161 -0
- package/clis/tvmaze/search.js +61 -0
- package/clis/tvmaze/show.js +60 -0
- package/clis/tvmaze/tvmaze.test.js +93 -0
- package/clis/tvmaze/utils.js +110 -0
- package/clis/twitter/accept.js +1 -1
- package/clis/twitter/followers.js +134 -69
- package/clis/twitter/reply-dm.js +1 -1
- package/clis/twitter/reply.test.js +1 -29
- package/clis/uisdc/news.js +105 -0
- package/clis/uisdc/news.test.js +66 -0
- package/clis/wanfang/search.js +0 -1
- package/clis/web/read.js +47 -17
- package/clis/web/read.test.js +101 -1
- package/clis/weixin/create-draft.js +1 -1
- package/clis/weixin/drafts.js +1 -1
- package/clis/weixin/drafts.test.js +5 -1
- package/clis/weixin/search.js +157 -0
- package/clis/weixin/search.test.js +227 -0
- package/clis/wikidata/entity.js +60 -0
- package/clis/wikidata/search.js +50 -0
- package/clis/wikidata/utils.js +117 -0
- package/clis/wikidata/wikidata.test.js +83 -0
- package/clis/wikipedia/page.js +95 -0
- package/clis/wttr/current.js +63 -0
- package/clis/wttr/forecast.js +71 -0
- package/clis/wttr/utils.js +50 -0
- package/clis/wttr/wttr.test.js +84 -0
- package/clis/xianyu/chat.js +16 -4
- package/clis/xianyu/chat.test.js +64 -0
- package/clis/xianyu/publish.js +485 -0
- package/clis/xianyu/publish.test.js +220 -0
- package/clis/xiaoe/catalog.js +105 -40
- package/clis/xiaoe/content.js +164 -29
- package/clis/xiaoe/courses.js +86 -29
- package/clis/xiaoe/xiaoe.test.js +486 -0
- package/clis/xiaohongshu/creator-notes-summary.js +1 -1
- package/clis/xiaohongshu/publish.js +16 -3
- package/clis/xiaohongshu/publish.test.js +46 -1
- package/clis/youtube/transcript.js +13 -19
- package/clis/youtube/transcript.test.js +17 -0
- package/clis/yuanbao/ask.js +17 -66
- package/clis/yuanbao/ask.test.js +5 -5
- package/clis/yuanbao/detail.js +65 -0
- package/clis/yuanbao/history.js +51 -0
- package/clis/yuanbao/new.js +1 -0
- package/clis/yuanbao/read.js +38 -0
- package/clis/yuanbao/send.js +57 -0
- package/clis/yuanbao/shared.js +297 -5
- package/clis/yuanbao/shared.test.js +80 -0
- package/clis/yuanbao/status.js +44 -0
- package/clis/zlibrary/commands.test.js +1 -11
- package/dist/src/browser/base-page.d.ts +9 -0
- package/dist/src/browser/base-page.js +44 -1
- package/dist/src/browser/base-page.test.js +66 -0
- package/dist/src/browser/cdp.d.ts +1 -0
- package/dist/src/browser/cdp.js +51 -9
- package/dist/src/browser/daemon-client.d.ts +4 -0
- package/dist/src/browser/errors.js +1 -1
- package/dist/src/browser/page.d.ts +1 -1
- package/dist/src/browser/page.js +3 -1
- package/dist/src/browser/page.test.js +29 -0
- package/dist/src/browser/target-errors.d.ts +2 -1
- package/dist/src/browser/target-errors.js +1 -0
- package/dist/src/browser/target-resolver.d.ts +25 -0
- package/dist/src/browser/target-resolver.js +43 -0
- package/dist/src/build-manifest.js +9 -4
- package/dist/src/build-manifest.test.js +2 -8
- package/dist/src/capabilityRouting.d.ts +16 -1
- package/dist/src/capabilityRouting.js +24 -1
- package/dist/src/capabilityRouting.test.js +19 -1
- package/dist/src/cli.js +76 -11
- package/dist/src/cli.test.js +150 -0
- package/dist/src/commanderAdapter.js +0 -5
- package/dist/src/commanderAdapter.test.js +0 -1
- package/dist/src/discovery.js +2 -5
- package/dist/src/errors.js +1 -1
- package/dist/src/execution.d.ts +1 -1
- package/dist/src/execution.js +111 -27
- package/dist/src/execution.test.js +326 -17
- package/dist/src/help.d.ts +23 -2
- package/dist/src/help.js +41 -19
- package/dist/src/help.test.d.ts +1 -0
- package/dist/src/help.test.js +54 -0
- package/dist/src/main.js +14 -1
- package/dist/src/manifest-types.d.ts +5 -3
- package/dist/src/pipeline/executor.js +1 -1
- package/dist/src/pipeline/executor.test.js +8 -0
- package/dist/src/pipeline/registry.d.ts +9 -0
- package/dist/src/pipeline/registry.js +13 -1
- package/dist/src/pipeline/steps/browser.d.ts +1 -0
- package/dist/src/pipeline/steps/browser.js +10 -0
- package/dist/src/pipeline/steps/download.test.js +1 -0
- package/dist/src/registry-api.d.ts +1 -1
- package/dist/src/registry.d.ts +12 -11
- package/dist/src/registry.js +16 -6
- package/dist/src/registry.test.js +2 -2
- package/dist/src/runtime.d.ts +2 -1
- package/dist/src/runtime.js +1 -1
- package/dist/src/serialization.d.ts +2 -2
- package/dist/src/serialization.js +4 -6
- package/dist/src/serialization.test.js +17 -0
- package/dist/src/types.d.ts +17 -0
- package/dist/src/validate.js +15 -11
- package/dist/src/validate.test.d.ts +9 -0
- package/dist/src/validate.test.js +90 -0
- package/package.json +1 -1
- package/scripts/fetch-adapters.js +1 -1
- package/scripts/typed-error-lint-baseline.json +5 -77
- package/clis/ctrip/search.test.js +0 -64
- package/clis/gov-policy/commands.test.js +0 -27
- package/clis/linux-do/category.js +0 -37
- package/clis/linux-do/hot.js +0 -26
- package/clis/linux-do/latest.js +0 -19
- package/clis/pixiv/test-utils.js +0 -23
- package/clis/toutiao/articles.test.js +0 -30
- package/dist/src/analysis.d.ts +0 -40
- package/dist/src/analysis.js +0 -172
package/clis/chatwise/send.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
2
|
import { selectorError } from '@jackwener/opencli/errors';
|
|
3
|
+
import { buildChatwiseInjectTextJs } from './utils.js';
|
|
3
4
|
export const sendCommand = cli({
|
|
4
5
|
site: 'chatwise',
|
|
5
6
|
name: 'send',
|
|
@@ -12,30 +13,7 @@ export const sendCommand = cli({
|
|
|
12
13
|
columns: ['Status', 'InjectedText'],
|
|
13
14
|
func: async (page, kwargs) => {
|
|
14
15
|
const text = kwargs.text;
|
|
15
|
-
const injected = await page.evaluate(
|
|
16
|
-
(function(text) {
|
|
17
|
-
// ChatWise input can be textarea or contenteditable
|
|
18
|
-
let composer = document.querySelector('textarea');
|
|
19
|
-
if (!composer) {
|
|
20
|
-
const editables = Array.from(document.querySelectorAll('[contenteditable="true"]'));
|
|
21
|
-
composer = editables.length > 0 ? editables[editables.length - 1] : null;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (!composer) return false;
|
|
25
|
-
|
|
26
|
-
composer.focus();
|
|
27
|
-
|
|
28
|
-
if (composer.tagName === 'TEXTAREA') {
|
|
29
|
-
// For textarea, set value and dispatch input event
|
|
30
|
-
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value').set;
|
|
31
|
-
nativeInputValueSetter.call(composer, text);
|
|
32
|
-
composer.dispatchEvent(new Event('input', { bubbles: true }));
|
|
33
|
-
} else {
|
|
34
|
-
document.execCommand('insertText', false, text);
|
|
35
|
-
}
|
|
36
|
-
return true;
|
|
37
|
-
})(${JSON.stringify(text)})
|
|
38
|
-
`);
|
|
16
|
+
const injected = await page.evaluate(buildChatwiseInjectTextJs(text));
|
|
39
17
|
if (!injected)
|
|
40
18
|
throw selectorError('ChatWise input element');
|
|
41
19
|
await page.wait(0.5);
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { ArgumentError } from '@jackwener/opencli/errors';
|
|
2
|
+
|
|
3
|
+
export const MESSAGE_WRAPPER_SELECTOR = '[class*="group/message"]';
|
|
4
|
+
export const MIN_COMPOSER_SCORE = 120;
|
|
5
|
+
|
|
6
|
+
export function requirePositiveTimeout(value) {
|
|
7
|
+
const timeout = value;
|
|
8
|
+
if (!Number.isInteger(timeout) || timeout <= 0) {
|
|
9
|
+
throw new ArgumentError('--timeout must be a positive integer (seconds)');
|
|
10
|
+
}
|
|
11
|
+
return timeout;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function scoreChatwiseComposerCandidate(candidate, viewportHeight = 0) {
|
|
15
|
+
if (candidate.hidden) return -1000;
|
|
16
|
+
|
|
17
|
+
let score = 0;
|
|
18
|
+
const normalizedRole = String(candidate.role || '').toLowerCase();
|
|
19
|
+
if (normalizedRole === 'textbox') score += 10;
|
|
20
|
+
|
|
21
|
+
const normalizedClasses = `${candidate.classes || ''} ${candidate.editorClasses || ''} ${candidate.ariaLabel || ''}`.toLowerCase();
|
|
22
|
+
if (normalizedClasses.includes('cm-content')) score += 20;
|
|
23
|
+
if (normalizedClasses.includes('cm-editor')) score += 30;
|
|
24
|
+
if (normalizedClasses.includes('simple-editor')) score -= 140;
|
|
25
|
+
|
|
26
|
+
const searchableText = `${candidate.placeholder || ''} ${candidate.ariaLabel || ''} ${candidate.text || ''}`.toLowerCase();
|
|
27
|
+
if (searchableText.includes('enter a message here')) score += 220;
|
|
28
|
+
if (searchableText.includes('press ⏎ to send')) score += 80;
|
|
29
|
+
if (searchableText.includes('press enter to send')) score += 80;
|
|
30
|
+
if (searchableText.includes('message')) score += 20;
|
|
31
|
+
if (searchableText.includes('optional description')) score -= 140;
|
|
32
|
+
if (searchableText.includes('user context document')) score -= 220;
|
|
33
|
+
|
|
34
|
+
if (viewportHeight > 0 && candidate.rect) {
|
|
35
|
+
const bottom = candidate.rect.y + candidate.rect.h;
|
|
36
|
+
const distanceFromBottom = Math.abs(viewportHeight - bottom);
|
|
37
|
+
score += Math.max(0, 80 - distanceFromBottom / 8);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return score;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function selectBestChatwiseComposer(candidates, viewportHeight = 0, minScore = MIN_COMPOSER_SCORE) {
|
|
44
|
+
if (!Array.isArray(candidates) || candidates.length === 0) return null;
|
|
45
|
+
const best = [...candidates]
|
|
46
|
+
.sort((left, right) => {
|
|
47
|
+
const delta = scoreChatwiseComposerCandidate(right, viewportHeight)
|
|
48
|
+
- scoreChatwiseComposerCandidate(left, viewportHeight);
|
|
49
|
+
return delta !== 0 ? delta : left.index - right.index;
|
|
50
|
+
})[0] ?? null;
|
|
51
|
+
if (!best || scoreChatwiseComposerCandidate(best, viewportHeight) < minScore) return null;
|
|
52
|
+
return best;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function buildChatwiseInjectTextJs(text) {
|
|
56
|
+
const scoreFn = scoreChatwiseComposerCandidate.toString();
|
|
57
|
+
const selectFn = selectBestChatwiseComposer.toString();
|
|
58
|
+
const textJs = JSON.stringify(String(text ?? ''));
|
|
59
|
+
|
|
60
|
+
return `
|
|
61
|
+
(function(text) {
|
|
62
|
+
const scoreChatwiseComposerCandidate = ${scoreFn};
|
|
63
|
+
const selectBestChatwiseComposer = ${selectFn};
|
|
64
|
+
const MIN_COMPOSER_SCORE = ${MIN_COMPOSER_SCORE};
|
|
65
|
+
|
|
66
|
+
const composers = Array.from(document.querySelectorAll([
|
|
67
|
+
'textarea[aria-label*="message" i]',
|
|
68
|
+
'textarea[placeholder*="message" i]',
|
|
69
|
+
'[contenteditable="true"][role="textbox"]',
|
|
70
|
+
'[contenteditable="true"]'
|
|
71
|
+
].join(',')));
|
|
72
|
+
const candidates = composers.map((el, index) => {
|
|
73
|
+
const rect = el.getBoundingClientRect();
|
|
74
|
+
const editor = el.closest('.cm-editor');
|
|
75
|
+
const placeholderEl = editor?.querySelector('.cm-placeholder');
|
|
76
|
+
return {
|
|
77
|
+
index,
|
|
78
|
+
hidden: !(el.offsetWidth || el.offsetHeight || el.getClientRects().length),
|
|
79
|
+
role: el.getAttribute('role'),
|
|
80
|
+
classes: el.className || '',
|
|
81
|
+
editorClasses: editor?.className || '',
|
|
82
|
+
ariaLabel: el.getAttribute('aria-label') || '',
|
|
83
|
+
placeholder: placeholderEl?.getAttribute('aria-label') || placeholderEl?.textContent || el.getAttribute('placeholder') || '',
|
|
84
|
+
text: (el.textContent || '').trim(),
|
|
85
|
+
rect: { y: rect.y, h: rect.height },
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const best = selectBestChatwiseComposer(candidates, window.innerHeight, MIN_COMPOSER_SCORE);
|
|
90
|
+
if (!best) return false;
|
|
91
|
+
|
|
92
|
+
const composer = composers[best.index];
|
|
93
|
+
composer.focus();
|
|
94
|
+
|
|
95
|
+
if (composer.tagName === 'TEXTAREA') {
|
|
96
|
+
const setter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value')?.set;
|
|
97
|
+
if (setter) setter.call(composer, text);
|
|
98
|
+
else composer.value = text;
|
|
99
|
+
composer.dispatchEvent(new Event('input', { bubbles: true }));
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const selection = window.getSelection();
|
|
104
|
+
const range = document.createRange();
|
|
105
|
+
range.selectNodeContents(composer);
|
|
106
|
+
selection?.removeAllRanges();
|
|
107
|
+
selection?.addRange(range);
|
|
108
|
+
|
|
109
|
+
const inserted = document.execCommand?.('insertText', false, text);
|
|
110
|
+
if (!inserted) {
|
|
111
|
+
composer.textContent = text;
|
|
112
|
+
}
|
|
113
|
+
composer.dispatchEvent(new Event('input', { bubbles: true }));
|
|
114
|
+
return true;
|
|
115
|
+
})(${textJs})
|
|
116
|
+
`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function buildChatwiseMessageCountJs() {
|
|
120
|
+
return `
|
|
121
|
+
(function() {
|
|
122
|
+
return Array.from(document.querySelectorAll(${JSON.stringify(MESSAGE_WRAPPER_SELECTOR)}))
|
|
123
|
+
.map(node => (node.innerText || node.textContent || '').trim())
|
|
124
|
+
.filter(Boolean)
|
|
125
|
+
.length;
|
|
126
|
+
})()
|
|
127
|
+
`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function buildChatwiseResponseAfterJs(previousCount, userText) {
|
|
131
|
+
return `
|
|
132
|
+
(function(previousCount, userText) {
|
|
133
|
+
const messages = Array.from(document.querySelectorAll(${JSON.stringify(MESSAGE_WRAPPER_SELECTOR)}))
|
|
134
|
+
.map(node => (node.innerText || node.textContent || '').trim())
|
|
135
|
+
.filter(Boolean);
|
|
136
|
+
if (messages.length <= previousCount) return null;
|
|
137
|
+
const fresh = messages.slice(previousCount)
|
|
138
|
+
.filter(text => text && text !== userText);
|
|
139
|
+
if (fresh.length === 0) return null;
|
|
140
|
+
return fresh[fresh.length - 1];
|
|
141
|
+
})(${Number(previousCount) || 0}, ${JSON.stringify(String(userText ?? ''))})
|
|
142
|
+
`;
|
|
143
|
+
}
|
package/clis/claude/ask.js
CHANGED
|
@@ -14,8 +14,8 @@ export const askCommand = cli({
|
|
|
14
14
|
domain: CLAUDE_DOMAIN,
|
|
15
15
|
strategy: Strategy.COOKIE,
|
|
16
16
|
browser: true,
|
|
17
|
+
browserSession: { reuse: 'site' },
|
|
17
18
|
navigateBefore: false,
|
|
18
|
-
timeoutSeconds: 180,
|
|
19
19
|
args: [
|
|
20
20
|
{ name: 'prompt', positional: true, required: true, help: 'Prompt to send' },
|
|
21
21
|
{ name: 'timeout', type: 'int', default: 120, help: 'Max seconds to wait for response' },
|
package/clis/claude/detail.js
CHANGED
|
@@ -10,6 +10,7 @@ export const detailCommand = cli({
|
|
|
10
10
|
domain: CLAUDE_DOMAIN,
|
|
11
11
|
strategy: Strategy.COOKIE,
|
|
12
12
|
browser: true,
|
|
13
|
+
browserSession: { reuse: 'site' },
|
|
13
14
|
navigateBefore: false,
|
|
14
15
|
args: [
|
|
15
16
|
{ name: 'id', positional: true, required: true, help: 'Conversation ID (UUID from /chat/<id>)' },
|
package/clis/claude/history.js
CHANGED
|
@@ -10,6 +10,7 @@ export const historyCommand = cli({
|
|
|
10
10
|
domain: CLAUDE_DOMAIN,
|
|
11
11
|
strategy: Strategy.COOKIE,
|
|
12
12
|
browser: true,
|
|
13
|
+
browserSession: { reuse: 'site' },
|
|
13
14
|
navigateBefore: false,
|
|
14
15
|
args: [
|
|
15
16
|
{ name: 'limit', type: 'int', default: 20, help: 'Max conversations to show' },
|
package/clis/claude/new.js
CHANGED
package/clis/claude/read.js
CHANGED
package/clis/claude/send.js
CHANGED
|
@@ -10,6 +10,7 @@ export const sendCommand = cli({
|
|
|
10
10
|
domain: CLAUDE_DOMAIN,
|
|
11
11
|
strategy: Strategy.COOKIE,
|
|
12
12
|
browser: true,
|
|
13
|
+
browserSession: { reuse: 'site' },
|
|
13
14
|
navigateBefore: false,
|
|
14
15
|
args: [
|
|
15
16
|
{ name: 'prompt', positional: true, required: true, help: 'Prompt to send' },
|
package/clis/claude/status.js
CHANGED
package/clis/codex/ask.js
CHANGED
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
|
-
import { selectorError } from '@jackwener/opencli/errors';
|
|
2
|
+
import { ArgumentError, selectorError } from '@jackwener/opencli/errors';
|
|
3
|
+
import { conversationSelectionArgs, openCodexConversation } from './sidebar.js';
|
|
3
4
|
export const askCommand = cli({
|
|
4
5
|
site: 'codex',
|
|
5
6
|
name: 'ask',
|
|
6
7
|
access: 'write',
|
|
7
|
-
description: 'Send a prompt and wait for the AI response
|
|
8
|
+
description: 'Send a prompt to the current or selected Codex conversation and wait for the AI response',
|
|
8
9
|
domain: 'localhost',
|
|
9
10
|
strategy: Strategy.UI,
|
|
10
11
|
browser: true,
|
|
11
12
|
args: [
|
|
12
13
|
{ name: 'text', required: true, positional: true, help: 'Prompt to send' },
|
|
13
|
-
{ name: 'timeout', required: false, help: 'Max seconds to wait for response (default: 60)', default:
|
|
14
|
+
{ name: 'timeout', type: 'int', required: false, help: 'Max seconds to wait for response (default: 60)', default: 60 },
|
|
15
|
+
...conversationSelectionArgs,
|
|
14
16
|
],
|
|
15
|
-
columns: ['Role', 'Text'],
|
|
17
|
+
columns: ['Role', 'Project', 'Conversation', 'Text'],
|
|
16
18
|
func: async (page, kwargs) => {
|
|
17
19
|
const text = kwargs.text;
|
|
18
|
-
const timeout =
|
|
20
|
+
const timeout = kwargs.timeout;
|
|
21
|
+
if (!Number.isInteger(timeout) || timeout < 1) {
|
|
22
|
+
throw new ArgumentError('--timeout must be a positive integer (seconds)');
|
|
23
|
+
}
|
|
24
|
+
const selected = await openCodexConversation(page, kwargs);
|
|
19
25
|
// Snapshot the current content length before sending
|
|
20
26
|
const beforeLen = await page.evaluate(`
|
|
21
27
|
(function() {
|
|
@@ -60,13 +66,13 @@ export const askCommand = cli({
|
|
|
60
66
|
}
|
|
61
67
|
if (!response) {
|
|
62
68
|
return [
|
|
63
|
-
{ Role: 'User', Text: text },
|
|
64
|
-
{ Role: 'System', Text: `No response within ${timeout}s. The agent may still be working.` },
|
|
69
|
+
{ Role: 'User', Project: selected?.project || '', Conversation: selected?.conversation || '', Text: text },
|
|
70
|
+
{ Role: 'System', Project: selected?.project || '', Conversation: selected?.conversation || '', Text: `No response within ${timeout}s. The agent may still be working.` },
|
|
65
71
|
];
|
|
66
72
|
}
|
|
67
73
|
return [
|
|
68
|
-
{ Role: 'User', Text: text },
|
|
69
|
-
{ Role: 'Assistant', Text: response },
|
|
74
|
+
{ Role: 'User', Project: selected?.project || '', Conversation: selected?.conversation || '', Text: text },
|
|
75
|
+
{ Role: 'Assistant', Project: selected?.project || '', Conversation: selected?.conversation || '', Text: response },
|
|
70
76
|
];
|
|
71
77
|
},
|
|
72
78
|
});
|
package/clis/codex/history.js
CHANGED
|
@@ -1,44 +1,27 @@
|
|
|
1
1
|
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
|
+
import { EmptyResultError } from '@jackwener/opencli/errors';
|
|
3
|
+
import { flattenCodexProjects, readCodexProjects } from './sidebar.js';
|
|
2
4
|
export const historyCommand = cli({
|
|
3
5
|
site: 'codex',
|
|
4
6
|
name: 'history',
|
|
5
7
|
access: 'read',
|
|
6
|
-
description: 'List
|
|
8
|
+
description: 'List visible Codex conversation threads grouped by project',
|
|
7
9
|
domain: 'localhost',
|
|
8
10
|
strategy: Strategy.UI,
|
|
9
11
|
browser: true,
|
|
10
|
-
args: [
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
// Fallback: sidebar/nav links
|
|
25
|
-
if (results.length === 0) {
|
|
26
|
-
const nav = document.querySelector('nav, [role="navigation"], aside');
|
|
27
|
-
if (nav) {
|
|
28
|
-
const links = nav.querySelectorAll('a, button');
|
|
29
|
-
links.forEach((link, i) => {
|
|
30
|
-
const text = (link.textContent || '').trim().substring(0, 100);
|
|
31
|
-
if (text && text.length > 3) results.push({ Index: i + 1, Title: text });
|
|
32
|
-
});
|
|
33
|
-
}
|
|
12
|
+
args: [
|
|
13
|
+
{ name: 'project', required: false, help: 'Filter by project label or path' },
|
|
14
|
+
{ name: 'limit', required: false, help: 'Max conversations per project' },
|
|
15
|
+
],
|
|
16
|
+
columns: ['Project', 'Index', 'Title', 'Updated', 'Active'],
|
|
17
|
+
func: async (page, kwargs) => {
|
|
18
|
+
const projects = await readCodexProjects(page);
|
|
19
|
+
const rows = flattenCodexProjects(projects, kwargs);
|
|
20
|
+
if (rows.length === 0) {
|
|
21
|
+
throw new EmptyResultError('codex history', kwargs.project
|
|
22
|
+
? `No Codex conversations were visible for project "${kwargs.project}".`
|
|
23
|
+
: 'No Codex conversations were visible. Open the Codex sidebar and retry.');
|
|
34
24
|
}
|
|
35
|
-
|
|
36
|
-
return results;
|
|
37
|
-
})()
|
|
38
|
-
`);
|
|
39
|
-
if (items.length === 0) {
|
|
40
|
-
return [{ Index: 0, Title: 'No threads found. Try opening the thread list first.' }];
|
|
41
|
-
}
|
|
42
|
-
return items;
|
|
25
|
+
return rows;
|
|
43
26
|
},
|
|
44
27
|
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
|
+
import { EmptyResultError } from '@jackwener/opencli/errors';
|
|
3
|
+
import { flattenCodexProjects, readCodexProjects } from './sidebar.js';
|
|
4
|
+
|
|
5
|
+
export const projectsCommand = cli({
|
|
6
|
+
site: 'codex',
|
|
7
|
+
name: 'projects',
|
|
8
|
+
access: 'read',
|
|
9
|
+
description: 'List Codex projects and visible conversations from the sidebar',
|
|
10
|
+
domain: 'localhost',
|
|
11
|
+
strategy: Strategy.UI,
|
|
12
|
+
browser: true,
|
|
13
|
+
args: [
|
|
14
|
+
{ name: 'project', required: false, help: 'Filter by project label or path' },
|
|
15
|
+
{ name: 'limit', required: false, help: 'Max conversations per project' },
|
|
16
|
+
],
|
|
17
|
+
columns: ['Project', 'Index', 'Title', 'Updated', 'Active'],
|
|
18
|
+
func: async (page, kwargs) => {
|
|
19
|
+
const projects = await readCodexProjects(page);
|
|
20
|
+
const rows = flattenCodexProjects(projects, kwargs);
|
|
21
|
+
if (rows.length === 0) {
|
|
22
|
+
throw new EmptyResultError('codex projects', kwargs.project
|
|
23
|
+
? `No Codex projects matched "${kwargs.project}".`
|
|
24
|
+
: 'No Codex projects were visible. Open the Codex sidebar and retry.');
|
|
25
|
+
}
|
|
26
|
+
return rows;
|
|
27
|
+
},
|
|
28
|
+
});
|
package/clis/codex/read.js
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
|
+
import { conversationSelectionArgs, openCodexConversation } from './sidebar.js';
|
|
2
3
|
export const readCommand = cli({
|
|
3
4
|
site: 'codex',
|
|
4
5
|
name: 'read',
|
|
5
6
|
access: 'read',
|
|
6
|
-
description: 'Read the contents of the current Codex conversation thread',
|
|
7
|
+
description: 'Read the contents of the current or selected Codex conversation thread',
|
|
7
8
|
domain: 'localhost',
|
|
8
9
|
strategy: Strategy.UI,
|
|
9
10
|
browser: true,
|
|
10
|
-
args: [
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
args: [
|
|
12
|
+
...conversationSelectionArgs,
|
|
13
|
+
],
|
|
14
|
+
columns: ['Project', 'Conversation', 'Content'],
|
|
15
|
+
func: async (page, kwargs) => {
|
|
16
|
+
const selected = await openCodexConversation(page, kwargs);
|
|
13
17
|
const historyText = await page.evaluate(`
|
|
14
18
|
(function() {
|
|
15
19
|
const turns = Array.from(document.querySelectorAll('[data-content-search-turn-key]'));
|
|
@@ -28,6 +32,8 @@ export const readCommand = cli({
|
|
|
28
32
|
`);
|
|
29
33
|
return [
|
|
30
34
|
{
|
|
35
|
+
Project: selected?.project || '',
|
|
36
|
+
Conversation: selected?.conversation || '',
|
|
31
37
|
Content: historyText,
|
|
32
38
|
},
|
|
33
39
|
];
|
package/clis/codex/send.js
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
2
|
import { selectorError } from '@jackwener/opencli/errors';
|
|
3
|
+
import { conversationSelectionArgs, openCodexConversation } from './sidebar.js';
|
|
3
4
|
export const sendCommand = cli({
|
|
4
5
|
site: 'codex',
|
|
5
6
|
name: 'send',
|
|
6
7
|
access: 'write',
|
|
7
|
-
description: 'Send text/commands to the Codex AI composer',
|
|
8
|
+
description: 'Send text/commands to the current or selected Codex AI composer',
|
|
8
9
|
domain: 'localhost',
|
|
9
10
|
strategy: Strategy.UI,
|
|
10
11
|
browser: true,
|
|
11
|
-
args: [
|
|
12
|
-
|
|
12
|
+
args: [
|
|
13
|
+
{ name: 'text', required: true, positional: true, help: 'Text, command (e.g. /review), or skill (e.g. $imagegen)' },
|
|
14
|
+
...conversationSelectionArgs,
|
|
15
|
+
],
|
|
16
|
+
columns: ['Status', 'Project', 'Conversation', 'InjectedText'],
|
|
13
17
|
func: async (page, kwargs) => {
|
|
14
18
|
const textToInsert = kwargs.text;
|
|
19
|
+
const selected = await openCodexConversation(page, kwargs);
|
|
15
20
|
const injected = await page.evaluate(`
|
|
16
21
|
(function(text) {
|
|
17
22
|
let composer = document.querySelector('textarea, [contenteditable="true"]');
|
|
@@ -37,6 +42,8 @@ export const sendCommand = cli({
|
|
|
37
42
|
return [
|
|
38
43
|
{
|
|
39
44
|
Status: 'Success',
|
|
45
|
+
Project: selected?.project || '',
|
|
46
|
+
Conversation: selected?.conversation || '',
|
|
40
47
|
InjectedText: textToInsert,
|
|
41
48
|
},
|
|
42
49
|
];
|