@jackwener/opencli 1.7.7 → 1.7.9
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 +49 -14
- package/README.zh-CN.md +30 -10
- package/cli-manifest.json +782 -55
- package/clis/36kr/news.js +1 -1
- package/clis/amazon/discussion.js +37 -6
- package/clis/amazon/discussion.test.js +147 -32
- package/clis/apple-podcasts/commands.test.js +4 -4
- package/clis/apple-podcasts/episodes.js +1 -1
- package/clis/apple-podcasts/search.js +1 -1
- package/clis/apple-podcasts/top.js +1 -1
- package/clis/arxiv/paper.js +1 -1
- package/clis/arxiv/search.js +1 -1
- package/clis/band/mentions.js +3 -3
- package/clis/bbc/news.js +1 -1
- package/clis/bilibili/subtitle.js +2 -2
- package/clis/bloomberg/businessweek.js +1 -1
- package/clis/bloomberg/economics.js +1 -1
- package/clis/bloomberg/industries.js +1 -1
- package/clis/bloomberg/main.js +1 -1
- package/clis/bloomberg/markets.js +1 -1
- package/clis/bloomberg/opinions.js +1 -1
- package/clis/bloomberg/politics.js +1 -1
- package/clis/bloomberg/tech.js +1 -1
- package/clis/boss/search.js +49 -8
- package/clis/boss/search.test.js +78 -0
- package/clis/boss/send.js +3 -3
- package/clis/chatgpt/image.js +37 -8
- package/clis/chatgpt/image.test.js +92 -0
- package/clis/chatgpt/utils.js +39 -6
- package/clis/chatgpt/utils.test.js +63 -0
- package/clis/chatgpt-app/ask.js +4 -20
- package/clis/chatgpt-app/ax.js +135 -2
- package/clis/chatgpt-app/ax.test.js +35 -0
- package/clis/chatgpt-app/model.js +1 -1
- package/clis/chatgpt-app/new.js +1 -1
- package/clis/chatgpt-app/read.js +1 -1
- package/clis/chatgpt-app/send.js +3 -22
- package/clis/chatgpt-app/status.js +1 -1
- package/clis/chatwise/ask.js +2 -2
- package/clis/chatwise/model.js +2 -2
- package/clis/chatwise/send.js +2 -2
- package/clis/claude/ask.js +128 -0
- package/clis/claude/ask.test.js +338 -0
- package/clis/claude/commands.test.js +118 -0
- package/clis/claude/detail.js +29 -0
- package/clis/claude/history.js +31 -0
- package/clis/claude/new.js +21 -0
- package/clis/claude/read.js +24 -0
- package/clis/claude/send.js +41 -0
- package/clis/claude/status.js +24 -0
- package/clis/claude/utils.js +440 -0
- package/clis/claude/utils.test.js +148 -0
- package/clis/codex/ask.js +2 -2
- package/clis/codex/send.js +2 -2
- package/clis/ctrip/search.js +1 -1
- package/clis/ctrip/search.test.js +4 -4
- package/clis/cursor/ask.js +2 -2
- package/clis/cursor/composer.js +2 -2
- package/clis/cursor/send.js +2 -2
- package/clis/deepseek/ask.js +49 -10
- package/clis/deepseek/ask.test.js +150 -3
- package/clis/deepseek/utils.js +60 -22
- package/clis/deepseek/utils.test.js +124 -5
- package/clis/doubao/utils.js +53 -11
- package/clis/doubao/utils.test.js +22 -2
- package/clis/eastmoney/announcement.js +1 -1
- package/clis/eastmoney/convertible.js +1 -1
- package/clis/eastmoney/etf.js +1 -1
- package/clis/eastmoney/holders.js +1 -1
- package/clis/eastmoney/index-board.js +1 -1
- package/clis/eastmoney/kline.js +1 -1
- package/clis/eastmoney/kuaixun.js +1 -1
- package/clis/eastmoney/longhu.js +1 -1
- package/clis/eastmoney/money-flow.js +1 -1
- package/clis/eastmoney/northbound.js +1 -1
- package/clis/eastmoney/quote.js +1 -1
- package/clis/eastmoney/rank.js +1 -1
- package/clis/eastmoney/sectors.js +1 -1
- package/clis/facebook/marketplace-inbox.js +83 -0
- package/clis/facebook/marketplace-listings.js +83 -0
- package/clis/facebook/marketplace.test.js +91 -0
- package/clis/google/news.js +1 -1
- package/clis/google/suggest.js +1 -1
- package/clis/google/trends.js +1 -1
- package/clis/google-scholar/cite.js +74 -0
- package/clis/google-scholar/cite.test.js +47 -0
- package/clis/google-scholar/profile.js +92 -0
- package/clis/google-scholar/profile.test.js +49 -0
- package/clis/google-scholar/search.js +1 -1
- package/clis/google-scholar/search.test.js +15 -0
- package/clis/hf/top.js +1 -1
- package/clis/jd/item.js +679 -47
- package/clis/jd/item.test.js +318 -7
- package/clis/jd/item.test.ts +517 -0
- package/clis/lesswrong/comments.js +1 -1
- package/clis/lesswrong/curated.js +1 -1
- package/clis/lesswrong/frontpage.js +1 -1
- package/clis/lesswrong/new.js +1 -1
- package/clis/lesswrong/read.js +1 -1
- package/clis/lesswrong/sequences.js +1 -1
- package/clis/lesswrong/shortform.js +1 -1
- package/clis/lesswrong/tag.js +1 -1
- package/clis/lesswrong/tags.js +1 -1
- package/clis/lesswrong/top-month.js +1 -1
- package/clis/lesswrong/top-week.js +1 -1
- package/clis/lesswrong/top-year.js +1 -1
- package/clis/lesswrong/top.js +1 -1
- package/clis/lesswrong/user-posts.js +1 -1
- package/clis/lesswrong/user.js +1 -1
- package/clis/paperreview/commands.test.js +6 -6
- package/clis/paperreview/feedback.js +1 -1
- package/clis/paperreview/review.js +1 -1
- package/clis/paperreview/submit.js +1 -1
- package/clis/powerchina/search.js +250 -0
- package/clis/powerchina/search.test.js +67 -0
- package/clis/producthunt/posts.js +1 -1
- package/clis/producthunt/today.js +1 -1
- package/clis/sinablog/search.js +1 -1
- package/clis/sinafinance/news.js +1 -1
- package/clis/sinafinance/stock.js +6 -3
- package/clis/sinafinance/stock.test.js +59 -0
- package/clis/spotify/spotify.js +6 -6
- package/clis/substack/search.js +1 -1
- package/clis/toutiao/articles.js +80 -0
- package/clis/toutiao/articles.test.js +30 -0
- package/clis/twitter/followers.js +2 -2
- package/clis/twitter/following.js +224 -73
- package/clis/twitter/following.test.js +277 -0
- package/clis/twitter/post.js +184 -47
- package/clis/twitter/post.test.js +114 -34
- package/clis/uiverse/_shared.js +63 -4
- package/clis/uiverse/_shared.test.js +7 -0
- package/clis/uiverse/code.js +1 -0
- package/clis/uiverse/navigation.test.js +12 -0
- package/clis/uiverse/preview.js +1 -0
- package/clis/web/read.js +319 -81
- package/clis/web/read.test.js +221 -5
- package/clis/weibo/favorites.js +169 -0
- package/clis/weibo/favorites.test.js +114 -0
- package/clis/weibo/publish.js +282 -0
- package/clis/weibo/publish.test.js +183 -0
- package/clis/weixin/create-draft.js +225 -0
- package/clis/weixin/drafts.js +65 -0
- package/clis/weixin/drafts.test.js +65 -0
- package/clis/weread/ranking.js +1 -1
- package/clis/weread/search-regression.test.js +8 -8
- package/clis/weread/search.js +1 -1
- package/clis/wikipedia/random.js +1 -1
- package/clis/wikipedia/search.js +1 -1
- package/clis/wikipedia/summary.js +1 -1
- package/clis/wikipedia/trending.js +1 -1
- package/clis/xianyu/chat.js +3 -3
- package/clis/xianyu/item.js +2 -2
- package/clis/xianyu/item.test.js +3 -3
- package/clis/xiaohongshu/search.js +17 -2
- package/clis/xiaohongshu/search.test.js +37 -1
- package/clis/xiaoyuzhou/download.js +1 -1
- package/clis/xiaoyuzhou/download.test.js +3 -3
- package/clis/xiaoyuzhou/episode.js +1 -1
- package/clis/xiaoyuzhou/podcast-episodes.js +1 -1
- package/clis/xiaoyuzhou/podcast-episodes.test.js +2 -2
- package/clis/xiaoyuzhou/podcast.js +1 -1
- package/clis/xiaoyuzhou/transcript.js +1 -1
- package/clis/xiaoyuzhou/transcript.test.js +5 -5
- package/clis/yollomi/models.js +1 -1
- package/clis/youtube/channel.js +24 -1
- package/clis/youtube/channel.test.js +59 -0
- package/clis/zhihu/answer.js +21 -162
- package/clis/zhihu/answer.test.js +26 -53
- package/clis/zhihu/collection.js +197 -0
- package/clis/zhihu/collection.test.js +290 -0
- package/clis/zhihu/collections.js +127 -0
- package/clis/zhihu/collections.test.js +182 -0
- package/clis/zhihu/comment.js +24 -305
- package/clis/zhihu/comment.test.js +31 -35
- package/clis/zhihu/favorite.js +44 -182
- package/clis/zhihu/favorite.test.js +30 -167
- package/clis/zhihu/follow.js +25 -56
- package/clis/zhihu/follow.test.js +20 -23
- package/clis/zhihu/like.js +22 -67
- package/clis/zhihu/like.test.js +19 -42
- package/clis/zhihu/search.js +3 -2
- package/clis/zhihu/write-shared.js +8 -1
- package/clis/zhihu/write-shared.test.js +1 -0
- package/clis/zlibrary/commands.test.js +75 -0
- package/clis/zlibrary/info.js +47 -0
- package/clis/zlibrary/search.js +46 -0
- package/clis/zlibrary/utils.js +136 -0
- package/dist/src/adapter-source.d.ts +11 -0
- package/dist/src/adapter-source.js +24 -0
- package/dist/src/adapter-source.test.js +29 -0
- package/dist/src/browser/base-page.d.ts +3 -1
- package/dist/src/browser/base-page.js +76 -1
- package/dist/src/browser/base-page.test.d.ts +1 -0
- package/dist/src/browser/base-page.test.js +74 -0
- package/dist/src/browser/bridge.d.ts +1 -0
- package/dist/src/browser/bridge.js +36 -9
- package/dist/src/browser/cdp.d.ts +1 -0
- package/dist/src/browser/cdp.js +3 -3
- package/dist/src/browser/daemon-client.d.ts +38 -4
- package/dist/src/browser/daemon-client.js +24 -7
- package/dist/src/browser/daemon-client.test.js +49 -0
- package/dist/src/browser/errors.js +3 -0
- package/dist/src/browser/errors.test.js +3 -0
- package/dist/src/browser/network-cache.d.ts +1 -0
- package/dist/src/browser/page.d.ts +3 -1
- package/dist/src/browser/page.js +10 -2
- package/dist/src/browser/profile.d.ts +14 -0
- package/dist/src/browser/profile.js +85 -0
- package/dist/src/build-manifest.d.ts +2 -0
- package/dist/src/build-manifest.js +13 -3
- package/dist/src/build-manifest.test.js +20 -2
- package/dist/src/cli.d.ts +6 -0
- package/dist/src/cli.js +462 -32
- package/dist/src/cli.test.js +209 -2
- package/dist/src/commanderAdapter.js +29 -9
- package/dist/src/commanderAdapter.test.js +78 -2
- package/dist/src/commands/daemon.js +6 -0
- package/dist/src/completion-shared.js +1 -2
- package/dist/src/completion.test.js +3 -2
- package/dist/src/daemon.js +125 -41
- package/dist/src/doctor.d.ts +4 -6
- package/dist/src/doctor.js +80 -22
- package/dist/src/doctor.test.js +82 -0
- package/dist/src/engine.test.js +6 -5
- package/dist/src/errors.d.ts +14 -8
- package/dist/src/errors.js +36 -30
- package/dist/src/errors.test.js +5 -5
- package/dist/src/execution.d.ts +4 -0
- package/dist/src/execution.js +173 -25
- package/dist/src/execution.test.js +171 -1
- package/dist/src/main.js +10 -0
- package/dist/src/observation/artifact.d.ts +16 -0
- package/dist/src/observation/artifact.js +260 -0
- package/dist/src/observation/artifact.test.d.ts +1 -0
- package/dist/src/observation/artifact.test.js +121 -0
- package/dist/src/observation/events.d.ts +89 -0
- package/dist/src/observation/events.js +1 -0
- package/dist/src/observation/index.d.ts +7 -0
- package/dist/src/observation/index.js +7 -0
- package/dist/src/observation/manager.d.ts +9 -0
- package/dist/src/observation/manager.js +27 -0
- package/dist/src/observation/manager.test.d.ts +1 -0
- package/dist/src/observation/manager.test.js +13 -0
- package/dist/src/observation/redaction.d.ts +11 -0
- package/dist/src/observation/redaction.js +81 -0
- package/dist/src/observation/redaction.test.d.ts +1 -0
- package/dist/src/observation/redaction.test.js +32 -0
- package/dist/src/observation/retention.d.ts +32 -0
- package/dist/src/observation/retention.js +160 -0
- package/dist/src/observation/retention.test.d.ts +1 -0
- package/dist/src/observation/retention.test.js +118 -0
- package/dist/src/observation/ring-buffer.d.ts +22 -0
- package/dist/src/observation/ring-buffer.js +45 -0
- package/dist/src/observation/ring-buffer.test.d.ts +1 -0
- package/dist/src/observation/ring-buffer.test.js +22 -0
- package/dist/src/observation/session.d.ts +25 -0
- package/dist/src/observation/session.js +50 -0
- package/dist/src/pipeline/executor.test.js +1 -0
- package/dist/src/pipeline/steps/download.test.js +1 -0
- package/dist/src/pipeline/steps/fetch.js +1 -21
- package/dist/src/pipeline/steps/fetch.test.js +6 -12
- package/dist/src/plugin-scaffold.js +1 -1
- package/dist/src/plugin-scaffold.test.js +1 -1
- package/dist/src/registry.d.ts +40 -9
- package/dist/src/registry.js +3 -1
- package/dist/src/runtime-detect.d.ts +10 -0
- package/dist/src/runtime-detect.js +19 -0
- package/dist/src/runtime-detect.test.js +12 -1
- package/dist/src/runtime.d.ts +2 -0
- package/dist/src/runtime.js +1 -0
- package/dist/src/types.d.ts +22 -0
- package/dist/src/update-check.d.ts +31 -1
- package/dist/src/update-check.js +62 -16
- package/dist/src/update-check.test.js +86 -1
- package/package.json +1 -1
- package/dist/src/diagnostic.d.ts +0 -63
- package/dist/src/diagnostic.js +0 -292
- package/dist/src/diagnostic.test.js +0 -302
- /package/dist/src/{diagnostic.test.d.ts → adapter-source.test.d.ts} +0 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { ArgumentError, AuthRequiredError, EmptyResultError } from '@jackwener/opencli/errors';
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
mockEnsureOnClaude,
|
|
6
|
+
mockEnsureClaudeComposer,
|
|
7
|
+
mockEnsureClaudeLogin,
|
|
8
|
+
mockSendMessage,
|
|
9
|
+
mockParseBoolFlag,
|
|
10
|
+
mockRequireNonEmptyPrompt,
|
|
11
|
+
mockGetVisibleMessages,
|
|
12
|
+
mockGetConversationList,
|
|
13
|
+
mockRequirePositiveInt,
|
|
14
|
+
mockRequireConversationId,
|
|
15
|
+
mockWithRetry,
|
|
16
|
+
} = vi.hoisted(() => ({
|
|
17
|
+
mockEnsureOnClaude: vi.fn(),
|
|
18
|
+
mockEnsureClaudeComposer: vi.fn(),
|
|
19
|
+
mockEnsureClaudeLogin: vi.fn(),
|
|
20
|
+
mockSendMessage: vi.fn(),
|
|
21
|
+
mockParseBoolFlag: vi.fn((v) => v === true || v === 'true'),
|
|
22
|
+
mockRequireNonEmptyPrompt: vi.fn((v) => String(v ?? '')),
|
|
23
|
+
mockGetVisibleMessages: vi.fn(),
|
|
24
|
+
mockGetConversationList: vi.fn(),
|
|
25
|
+
mockRequirePositiveInt: vi.fn((v) => Number(v)),
|
|
26
|
+
mockRequireConversationId: vi.fn((v) => String(v ?? '').trim()),
|
|
27
|
+
mockWithRetry: vi.fn(async (fn) => fn()),
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
vi.mock('./utils.js', () => ({
|
|
31
|
+
CLAUDE_DOMAIN: 'claude.ai',
|
|
32
|
+
CLAUDE_URL: 'https://claude.ai/new',
|
|
33
|
+
ensureOnClaude: mockEnsureOnClaude,
|
|
34
|
+
ensureClaudeComposer: mockEnsureClaudeComposer,
|
|
35
|
+
ensureClaudeLogin: mockEnsureClaudeLogin,
|
|
36
|
+
sendMessage: mockSendMessage,
|
|
37
|
+
parseBoolFlag: mockParseBoolFlag,
|
|
38
|
+
requireNonEmptyPrompt: mockRequireNonEmptyPrompt,
|
|
39
|
+
getVisibleMessages: mockGetVisibleMessages,
|
|
40
|
+
getConversationList: mockGetConversationList,
|
|
41
|
+
requirePositiveInt: mockRequirePositiveInt,
|
|
42
|
+
requireConversationId: mockRequireConversationId,
|
|
43
|
+
withRetry: mockWithRetry,
|
|
44
|
+
}));
|
|
45
|
+
|
|
46
|
+
import { sendCommand } from './send.js';
|
|
47
|
+
import { newCommand } from './new.js';
|
|
48
|
+
import { readCommand } from './read.js';
|
|
49
|
+
import { historyCommand } from './history.js';
|
|
50
|
+
import { detailCommand } from './detail.js';
|
|
51
|
+
|
|
52
|
+
describe('claude command-level fail-fast contracts', () => {
|
|
53
|
+
const page = {
|
|
54
|
+
goto: vi.fn().mockResolvedValue(undefined),
|
|
55
|
+
wait: vi.fn().mockResolvedValue(undefined),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
vi.clearAllMocks();
|
|
60
|
+
mockEnsureOnClaude.mockResolvedValue(false);
|
|
61
|
+
mockEnsureClaudeComposer.mockResolvedValue({ isLoggedIn: true, hasComposer: true });
|
|
62
|
+
mockEnsureClaudeLogin.mockResolvedValue({ isLoggedIn: true });
|
|
63
|
+
mockSendMessage.mockResolvedValue({ ok: true });
|
|
64
|
+
mockRequireNonEmptyPrompt.mockImplementation((v) => String(v ?? ''));
|
|
65
|
+
mockGetVisibleMessages.mockResolvedValue([{ Index: 0, Role: 'assistant', Text: 'hi' }]);
|
|
66
|
+
mockGetConversationList.mockResolvedValue([{ Index: 1, Id: 'abc', Title: 'Hi', Url: 'https://claude.ai/chat/abc' }]);
|
|
67
|
+
mockRequirePositiveInt.mockImplementation((v) => Number(v));
|
|
68
|
+
mockRequireConversationId.mockImplementation((v) => String(v ?? '').trim());
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('send rejects empty prompt via ArgumentError', async () => {
|
|
72
|
+
mockRequireNonEmptyPrompt.mockImplementation(() => {
|
|
73
|
+
throw new ArgumentError('claude send prompt cannot be empty');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
await expect(sendCommand.func(page, { prompt: '', new: false })).rejects.toThrow(ArgumentError);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('send surfaces auth failure from composer readiness', async () => {
|
|
80
|
+
mockEnsureClaudeComposer.mockRejectedValue(new AuthRequiredError('claude.ai', 'Claude send requires a logged-in Claude session.'));
|
|
81
|
+
|
|
82
|
+
await expect(sendCommand.func(page, { prompt: 'hi', new: false })).rejects.toThrow(AuthRequiredError);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('new no longer false-succeeds on login wall', async () => {
|
|
86
|
+
mockEnsureClaudeComposer.mockRejectedValue(new AuthRequiredError('claude.ai', 'Claude new requires a logged-in Claude session with a visible composer.'));
|
|
87
|
+
|
|
88
|
+
await expect(newCommand.func(page)).rejects.toThrow(AuthRequiredError);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('read throws EmptyResultError instead of a placeholder row', async () => {
|
|
92
|
+
mockGetVisibleMessages.mockResolvedValue([]);
|
|
93
|
+
|
|
94
|
+
await expect(readCommand.func(page)).rejects.toThrow(EmptyResultError);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('history rejects invalid --limit values instead of silently coercing them', async () => {
|
|
98
|
+
mockRequirePositiveInt.mockImplementation(() => {
|
|
99
|
+
throw new ArgumentError('claude history --limit must be a positive integer');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
await expect(historyCommand.func(page, { limit: 0 })).rejects.toThrow(ArgumentError);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('history throws EmptyResultError on an empty /recents page', async () => {
|
|
106
|
+
mockGetConversationList.mockResolvedValue([]);
|
|
107
|
+
|
|
108
|
+
await expect(historyCommand.func(page, { limit: 20 })).rejects.toThrow(EmptyResultError);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('detail rejects a missing conversation id', async () => {
|
|
112
|
+
mockRequireConversationId.mockImplementation(() => {
|
|
113
|
+
throw new ArgumentError('claude detail requires a conversation id');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
await expect(detailCommand.func(page, { id: '' })).rejects.toThrow(ArgumentError);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
|
+
import { EmptyResultError } from '@jackwener/opencli/errors';
|
|
3
|
+
import { CLAUDE_DOMAIN, getVisibleMessages, ensureClaudeLogin, requireConversationId } from './utils.js';
|
|
4
|
+
|
|
5
|
+
export const detailCommand = cli({
|
|
6
|
+
site: 'claude',
|
|
7
|
+
name: 'detail',
|
|
8
|
+
description: 'Open a Claude conversation by ID and read its messages',
|
|
9
|
+
domain: CLAUDE_DOMAIN,
|
|
10
|
+
strategy: Strategy.COOKIE,
|
|
11
|
+
browser: true,
|
|
12
|
+
navigateBefore: false,
|
|
13
|
+
args: [
|
|
14
|
+
{ name: 'id', positional: true, required: true, help: 'Conversation ID (UUID from /chat/<id>)' },
|
|
15
|
+
],
|
|
16
|
+
columns: ['Index', 'Role', 'Text'],
|
|
17
|
+
|
|
18
|
+
func: async (page, kwargs) => {
|
|
19
|
+
const id = requireConversationId(kwargs.id);
|
|
20
|
+
|
|
21
|
+
await page.goto(`https://claude.ai/chat/${id}`);
|
|
22
|
+
await page.wait(4);
|
|
23
|
+
await ensureClaudeLogin(page, 'Claude detail requires a logged-in Claude session.');
|
|
24
|
+
|
|
25
|
+
const messages = await getVisibleMessages(page);
|
|
26
|
+
if (messages.length > 0) return messages;
|
|
27
|
+
throw new EmptyResultError('claude detail', `No visible Claude messages were found for conversation ${id}.`);
|
|
28
|
+
},
|
|
29
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
|
+
import { EmptyResultError } from '@jackwener/opencli/errors';
|
|
3
|
+
import { CLAUDE_DOMAIN, getConversationList, ensureClaudeLogin, requirePositiveInt } from './utils.js';
|
|
4
|
+
|
|
5
|
+
export const historyCommand = cli({
|
|
6
|
+
site: 'claude',
|
|
7
|
+
name: 'history',
|
|
8
|
+
description: 'List conversation history from Claude /recents',
|
|
9
|
+
domain: CLAUDE_DOMAIN,
|
|
10
|
+
strategy: Strategy.COOKIE,
|
|
11
|
+
browser: true,
|
|
12
|
+
navigateBefore: false,
|
|
13
|
+
args: [
|
|
14
|
+
{ name: 'limit', type: 'int', default: 20, help: 'Max conversations to show' },
|
|
15
|
+
],
|
|
16
|
+
columns: ['Index', 'Id', 'Title', 'Url'],
|
|
17
|
+
|
|
18
|
+
func: async (page, kwargs) => {
|
|
19
|
+
const limit = requirePositiveInt(
|
|
20
|
+
Number(kwargs.limit ?? 20),
|
|
21
|
+
'claude history --limit',
|
|
22
|
+
'Example: opencli claude history --limit 20',
|
|
23
|
+
);
|
|
24
|
+
const conversations = await getConversationList(page);
|
|
25
|
+
await ensureClaudeLogin(page, 'Claude history requires a logged-in Claude session.');
|
|
26
|
+
if (conversations.length === 0) {
|
|
27
|
+
throw new EmptyResultError('claude history', 'No Claude conversation history was visible on /recents.');
|
|
28
|
+
}
|
|
29
|
+
return conversations.slice(0, limit);
|
|
30
|
+
},
|
|
31
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
|
+
import { CLAUDE_DOMAIN, CLAUDE_URL, ensureClaudeComposer } from './utils.js';
|
|
3
|
+
|
|
4
|
+
export const newCommand = cli({
|
|
5
|
+
site: 'claude',
|
|
6
|
+
name: 'new',
|
|
7
|
+
description: 'Start a new conversation in Claude',
|
|
8
|
+
domain: CLAUDE_DOMAIN,
|
|
9
|
+
strategy: Strategy.COOKIE,
|
|
10
|
+
browser: true,
|
|
11
|
+
navigateBefore: false,
|
|
12
|
+
args: [],
|
|
13
|
+
columns: ['Status'],
|
|
14
|
+
|
|
15
|
+
func: async (page) => {
|
|
16
|
+
await page.goto(CLAUDE_URL);
|
|
17
|
+
await page.wait(2);
|
|
18
|
+
await ensureClaudeComposer(page, 'Claude new requires a logged-in Claude session with a visible composer.');
|
|
19
|
+
return [{ Status: 'New chat started' }];
|
|
20
|
+
},
|
|
21
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
|
+
import { EmptyResultError } from '@jackwener/opencli/errors';
|
|
3
|
+
import { CLAUDE_DOMAIN, ensureOnClaude, getVisibleMessages, ensureClaudeLogin } from './utils.js';
|
|
4
|
+
|
|
5
|
+
export const readCommand = cli({
|
|
6
|
+
site: 'claude',
|
|
7
|
+
name: 'read',
|
|
8
|
+
description: 'Read the current Claude conversation',
|
|
9
|
+
domain: CLAUDE_DOMAIN,
|
|
10
|
+
strategy: Strategy.COOKIE,
|
|
11
|
+
browser: true,
|
|
12
|
+
navigateBefore: false,
|
|
13
|
+
args: [],
|
|
14
|
+
columns: ['Index', 'Role', 'Text'],
|
|
15
|
+
|
|
16
|
+
func: async (page) => {
|
|
17
|
+
await ensureOnClaude(page);
|
|
18
|
+
await page.wait(3);
|
|
19
|
+
await ensureClaudeLogin(page, 'Claude read requires a logged-in Claude session.');
|
|
20
|
+
const messages = await getVisibleMessages(page);
|
|
21
|
+
if (messages.length > 0) return messages;
|
|
22
|
+
throw new EmptyResultError('claude read', 'No visible Claude messages were found in the current conversation.');
|
|
23
|
+
},
|
|
24
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
|
+
import { CommandExecutionError } from '@jackwener/opencli/errors';
|
|
3
|
+
import { CLAUDE_DOMAIN, CLAUDE_URL, ensureOnClaude, sendMessage, parseBoolFlag, withRetry, ensureClaudeComposer, requireNonEmptyPrompt } from './utils.js';
|
|
4
|
+
|
|
5
|
+
export const sendCommand = cli({
|
|
6
|
+
site: 'claude',
|
|
7
|
+
name: 'send',
|
|
8
|
+
description: 'Send a prompt to Claude without waiting for the response',
|
|
9
|
+
domain: CLAUDE_DOMAIN,
|
|
10
|
+
strategy: Strategy.COOKIE,
|
|
11
|
+
browser: true,
|
|
12
|
+
navigateBefore: false,
|
|
13
|
+
args: [
|
|
14
|
+
{ name: 'prompt', positional: true, required: true, help: 'Prompt to send' },
|
|
15
|
+
{ name: 'new', type: 'boolean', default: false, help: 'Start a new chat before sending' },
|
|
16
|
+
],
|
|
17
|
+
columns: ['Status', 'SubmittedBy', 'InjectedText'],
|
|
18
|
+
|
|
19
|
+
func: async (page, kwargs) => {
|
|
20
|
+
const prompt = requireNonEmptyPrompt(kwargs.prompt, 'claude send');
|
|
21
|
+
|
|
22
|
+
if (parseBoolFlag(kwargs.new)) {
|
|
23
|
+
await page.goto(CLAUDE_URL);
|
|
24
|
+
await page.wait(3);
|
|
25
|
+
} else {
|
|
26
|
+
await ensureOnClaude(page);
|
|
27
|
+
await page.wait(2);
|
|
28
|
+
}
|
|
29
|
+
await withRetry(() => ensureClaudeComposer(page, 'Claude send requires a visible composer on the current page.'));
|
|
30
|
+
|
|
31
|
+
const sendResult = await withRetry(() => sendMessage(page, prompt));
|
|
32
|
+
if (!sendResult?.ok) {
|
|
33
|
+
throw new CommandExecutionError(sendResult?.reason || 'Failed to send message');
|
|
34
|
+
}
|
|
35
|
+
return [{
|
|
36
|
+
Status: 'Success',
|
|
37
|
+
SubmittedBy: sendResult.method || 'send-button',
|
|
38
|
+
InjectedText: prompt,
|
|
39
|
+
}];
|
|
40
|
+
},
|
|
41
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
2
|
+
import { CLAUDE_DOMAIN, ensureOnClaude, getPageState } from './utils.js';
|
|
3
|
+
|
|
4
|
+
export const statusCommand = cli({
|
|
5
|
+
site: 'claude',
|
|
6
|
+
name: 'status',
|
|
7
|
+
description: 'Check Claude page availability and login state',
|
|
8
|
+
domain: CLAUDE_DOMAIN,
|
|
9
|
+
strategy: Strategy.COOKIE,
|
|
10
|
+
browser: true,
|
|
11
|
+
navigateBefore: false,
|
|
12
|
+
args: [],
|
|
13
|
+
columns: ['Status', 'Login', 'Url'],
|
|
14
|
+
|
|
15
|
+
func: async (page) => {
|
|
16
|
+
await ensureOnClaude(page);
|
|
17
|
+
const state = await getPageState(page);
|
|
18
|
+
return [{
|
|
19
|
+
Status: state.hasComposer ? 'Connected' : 'Page not ready',
|
|
20
|
+
Login: state.isLoggedIn ? 'Yes' : 'No',
|
|
21
|
+
Url: state.url,
|
|
22
|
+
}];
|
|
23
|
+
},
|
|
24
|
+
});
|