@jackwener/opencli 0.8.0 → 0.9.1

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.
Files changed (68) hide show
  1. package/README.md +7 -2
  2. package/README.zh-CN.md +9 -2
  3. package/SKILL.md +11 -2
  4. package/dist/cli-manifest.json +343 -0
  5. package/dist/clis/antigravity/dump.d.ts +1 -0
  6. package/dist/clis/antigravity/dump.js +28 -0
  7. package/dist/clis/antigravity/extract-code.d.ts +1 -0
  8. package/dist/clis/antigravity/extract-code.js +32 -0
  9. package/dist/clis/antigravity/model.d.ts +1 -0
  10. package/dist/clis/antigravity/model.js +44 -0
  11. package/dist/clis/antigravity/new.d.ts +1 -0
  12. package/dist/clis/antigravity/new.js +25 -0
  13. package/dist/clis/antigravity/read.d.ts +1 -0
  14. package/dist/clis/antigravity/read.js +34 -0
  15. package/dist/clis/antigravity/send.d.ts +1 -0
  16. package/dist/clis/antigravity/send.js +35 -0
  17. package/dist/clis/antigravity/status.d.ts +1 -0
  18. package/dist/clis/antigravity/status.js +18 -0
  19. package/dist/clis/antigravity/watch.d.ts +1 -0
  20. package/dist/clis/antigravity/watch.js +41 -0
  21. package/dist/clis/codex/dump.d.ts +1 -0
  22. package/dist/clis/codex/dump.js +25 -0
  23. package/dist/clis/codex/extract-diff.d.ts +1 -0
  24. package/dist/clis/codex/extract-diff.js +44 -0
  25. package/dist/clis/codex/new.d.ts +1 -0
  26. package/dist/clis/codex/new.js +25 -0
  27. package/dist/clis/codex/read.d.ts +1 -0
  28. package/dist/clis/codex/read.js +31 -0
  29. package/dist/clis/codex/send.d.ts +1 -0
  30. package/dist/clis/codex/send.js +44 -0
  31. package/dist/clis/codex/status.d.ts +1 -0
  32. package/dist/clis/codex/status.js +21 -0
  33. package/dist/clis/xiaoyuzhou/episode.d.ts +1 -0
  34. package/dist/clis/xiaoyuzhou/episode.js +28 -0
  35. package/dist/clis/xiaoyuzhou/podcast-episodes.d.ts +1 -0
  36. package/dist/clis/xiaoyuzhou/podcast-episodes.js +36 -0
  37. package/dist/clis/xiaoyuzhou/podcast.d.ts +1 -0
  38. package/dist/clis/xiaoyuzhou/podcast.js +27 -0
  39. package/dist/clis/xiaoyuzhou/utils.d.ts +16 -0
  40. package/dist/clis/xiaoyuzhou/utils.js +55 -0
  41. package/dist/clis/xiaoyuzhou/utils.test.d.ts +1 -0
  42. package/dist/clis/xiaoyuzhou/utils.test.js +99 -0
  43. package/package.json +1 -1
  44. package/src/clis/antigravity/README.md +49 -0
  45. package/src/clis/antigravity/README.zh-CN.md +52 -0
  46. package/src/clis/antigravity/SKILL.md +42 -0
  47. package/src/clis/antigravity/dump.ts +30 -0
  48. package/src/clis/antigravity/extract-code.ts +34 -0
  49. package/src/clis/antigravity/model.ts +47 -0
  50. package/src/clis/antigravity/new.ts +28 -0
  51. package/src/clis/antigravity/read.ts +36 -0
  52. package/src/clis/antigravity/send.ts +40 -0
  53. package/src/clis/antigravity/status.ts +19 -0
  54. package/src/clis/antigravity/watch.ts +45 -0
  55. package/src/clis/codex/README.md +33 -0
  56. package/src/clis/codex/README.zh-CN.md +33 -0
  57. package/src/clis/codex/dump.ts +28 -0
  58. package/src/clis/codex/extract-diff.ts +47 -0
  59. package/src/clis/codex/new.ts +29 -0
  60. package/src/clis/codex/read.ts +33 -0
  61. package/src/clis/codex/send.ts +48 -0
  62. package/src/clis/codex/status.ts +23 -0
  63. package/src/clis/xiaoyuzhou/episode.ts +28 -0
  64. package/src/clis/xiaoyuzhou/podcast-episodes.ts +36 -0
  65. package/src/clis/xiaoyuzhou/podcast.ts +27 -0
  66. package/src/clis/xiaoyuzhou/utils.test.ts +122 -0
  67. package/src/clis/xiaoyuzhou/utils.ts +65 -0
  68. package/tests/e2e/public-commands.test.ts +62 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # OpenCLI
2
2
 
3
- > **Make any website your CLI.**
3
+ > **Make any website or Electron App your CLI.**
4
4
  > Zero risk · Reuse Chrome login · AI-powered discovery · 80+ commands · 19 sites
5
5
 
6
6
  [中文文档](./README.zh-CN.md)
@@ -9,7 +9,10 @@
9
9
  [![Node.js Version](https://img.shields.io/node/v/@jackwener/opencli?style=flat-square)](https://nodejs.org)
10
10
  [![License](https://img.shields.io/npm/l/@jackwener/opencli?style=flat-square)](./LICENSE)
11
11
 
12
- A CLI tool that turns **any website** into a command-line interface — Bilibili, Zhihu, 小红书, Twitter/X, Reddit, YouTube, and [many more](#built-in-commands) — powered by browser session reuse and AI-native discovery.
12
+ A CLI tool that turns **any website** or **Electron app** into a command-line interface — Bilibili, Zhihu, 小红书, Twitter/X, Reddit, YouTube, Antigravity, and [many more](#built-in-commands) — powered by browser session reuse and AI-native discovery.
13
+
14
+ 🔥 **CLI All Electron Apps! The Most Powerful Update Has Arrived!** 🔥
15
+ Turn ANY Electron application into a CLI tool! Recombine, script, and extend applications like Antigravity Ultra seamlessly. Now AI can control itself natively. Unlimited possibilities await!
13
16
 
14
17
  ---
15
18
 
@@ -31,6 +34,7 @@ A CLI tool that turns **any website** into a command-line interface — Bilibili
31
34
 
32
35
  ## Highlights
33
36
 
37
+ - **CLI All Electron** — CLI-ify apps like Antigravity Ultra! Now AI can control itself natively using cc/openclaw!
34
38
  - **Account-safe** — Reuses Chrome's logged-in state; your credentials never leave the browser.
35
39
  - **AI Agent ready** — `explore` discovers APIs, `synthesize` generates adapters, `cascade` finds auth strategies.
36
40
  - **Self-healing setup** — `opencli setup` auto-discovers tokens; `opencli doctor` diagnoses config across 10+ tools; `--fix` repairs them all.
@@ -149,6 +153,7 @@ npm install -g @jackwener/opencli@latest
149
153
  | **v2ex** | `hot` `latest` `topic` `daily` `me` `notifications` | 6 | 🌐 / 🔐 |
150
154
  | **xueqiu** | `feed` `hot-stock` `hot` `search` `stock` `watchlist` | 6 | 🔐 Browser |
151
155
  | **xiaohongshu** | `search` `notifications` `feed` `me` `user` | 5 | 🔐 Browser |
156
+ | **xiaoyuzhou** | `podcast` `podcast-episodes` `episode` | 3 | 🌐 Public |
152
157
  | **youtube** | `search` `video` `transcript` | 3 | 🔐 Browser |
153
158
  | **zhihu** | `hot` `search` `question` | 3 | 🔐 Browser |
154
159
  | **boss** | `search` `detail` | 2 | 🔐 Browser |
package/README.zh-CN.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # OpenCLI
2
2
 
3
- > **把任何网站变成你的命令行工具。**
3
+ > **把任何网站或 Electron 应用变成你的命令行工具。**
4
4
  > 零风控 · 复用 Chrome 登录 · AI 自动发现接口 · 80+ 命令 · 19 站点
5
5
 
6
6
  [English](./README.md)
@@ -9,7 +9,12 @@
9
9
  [![Node.js Version](https://img.shields.io/node/v/@jackwener/opencli?style=flat-square)](https://nodejs.org)
10
10
  [![License](https://img.shields.io/npm/l/@jackwener/opencli?style=flat-square)](./LICENSE)
11
11
 
12
- OpenCLI 将任何网站变成命令行工具 — B站、知乎、小红书、Twitter/X、Reddit、YouTube 等 [19 个站点](#内置命令) — 复用浏览器登录态,AI 驱动探索。
12
+ OpenCLI 将任何网站或 Electron 应用(如 Antigravity)变成命令行工具 — B站、知乎、小红书、Twitter/X、Reddit、YouTube 等 [19 个站点](#内置命令) — 复用浏览器登录态,AI 驱动探索。
13
+
14
+ 🔥 **opencli 支持 CLI 化所有 electron 应用!最强大更新来袭!** 🔥
15
+ CLI all electron!现在支持把所有 electron 应用 CLI 化,从而组合出各种神奇的能力。
16
+ 如果你在使用诸如 Antigravity Ultra 等工具时觉得不够灵活或难以扩展,现在通过 OpenCLI 把他 CLI 化,轻松打破界限。
17
+ 现在,**AI 可以自己控制自己**!结合 cc/openclaw 就可以远程控制任何 electron 应用!无限玩法!!
13
18
 
14
19
  ---
15
20
 
@@ -30,6 +35,7 @@ OpenCLI 将任何网站变成命令行工具 — B站、知乎、小红书、Twi
30
35
 
31
36
  ## 亮点
32
37
 
38
+ - **CLI All Electron** — 支持把所有 electron 应用(如 Antigravity Ultra)CLI 化,让 AI 控制自己!
33
39
  - **多站点覆盖** — B站、知乎、小红书、Twitter、Reddit 等 19 个站点,80+ 命令
34
40
  - **零风控** — 复用 Chrome 登录态,无需存储任何凭证
35
41
  - **自修复配置** — `opencli setup` 自动发现 Token;`opencli doctor` 诊断 10+ 工具配置;`--fix` 一键修复
@@ -148,6 +154,7 @@ npm install -g @jackwener/opencli@latest
148
154
  | **v2ex** | `hot` `latest` `topic` `daily` `me` `notifications` | 6 | 🌐 / 🔐 |
149
155
  | **xueqiu** | `feed` `hot-stock` `hot` `search` `stock` `watchlist` | 6 | 🔐 浏览器 |
150
156
  | **xiaohongshu** | `search` `notifications` `feed` `me` `user` | 5 | 🔐 浏览器 |
157
+ | **xiaoyuzhou** | `podcast` `podcast-episodes` `episode` | 3 | 🌐 公开 |
151
158
  | **youtube** | `search` `video` `transcript` | 3 | 🔐 浏览器 |
152
159
  | **zhihu** | `hot` `search` `question` | 3 | 🔐 浏览器 |
153
160
  | **boss** | `search` `detail` | 2 | 🔐 浏览器 |
package/SKILL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: opencli
3
- description: "OpenCLI — Make any website your CLI. Zero risk, AI-powered, reuse Chrome login. 80+ commands across 19 sites."
3
+ description: "OpenCLI — Make any website or Electron App your CLI. Zero risk, AI-powered, reuse Chrome login. 80+ commands across 19 sites."
4
4
  version: 0.7.3
5
5
  author: jackwener
6
6
  tags: [cli, browser, web, mcp, playwright, bilibili, zhihu, twitter, github, v2ex, hackernews, reddit, xiaohongshu, xueqiu, youtube, boss, coupang, AI, agent]
@@ -8,7 +8,7 @@ tags: [cli, browser, web, mcp, playwright, bilibili, zhihu, twitter, github, v2e
8
8
 
9
9
  # OpenCLI
10
10
 
11
- > Make any website your CLI. Reuse Chrome login, zero risk, AI-powered discovery.
11
+ > Make any website or Electron App your CLI. Reuse Chrome login, zero risk, AI-powered discovery.
12
12
 
13
13
  > [!CAUTION]
14
14
  > **AI Agent 必读:创建或修改任何适配器之前,你必须先阅读 [CLI-EXPLORER.md](./CLI-EXPLORER.md)!**
@@ -151,6 +151,15 @@ opencli smzdm search --keyword "耳机" # 搜索好价
151
151
 
152
152
  # 携程 (browser)
153
153
  opencli ctrip search --query "三亚" # 搜索目的地
154
+
155
+ # Antigravity (Electron/CDP)
156
+ opencli antigravity status # 检查 CDP 连接
157
+ opencli antigravity send "hello" # 发送文本到当前 agent 聊天框
158
+ opencli antigravity read # 读取整个聊天记录面板
159
+ opencli antigravity new # 清空聊天、开启新对话
160
+ opencli antigravity extract-code # 自动抽取 AI 回复中的代码块
161
+ opencli antigravity model claude # 切换底层模型
162
+ opencli antigravity watch # 流式监听增量消息
154
163
  ```
155
164
 
156
165
  ### Management Commands
@@ -1,4 +1,142 @@
1
1
  [
2
+ {
3
+ "site": "antigravity",
4
+ "name": "dump",
5
+ "description": "Dump the DOM to help AI understand the UI",
6
+ "strategy": "ui",
7
+ "browser": true,
8
+ "args": [],
9
+ "type": "ts",
10
+ "modulePath": "antigravity/dump.js",
11
+ "domain": "localhost",
12
+ "columns": [
13
+ "htmlFile",
14
+ "snapFile"
15
+ ]
16
+ },
17
+ {
18
+ "site": "antigravity",
19
+ "name": "extract-code",
20
+ "description": "Extract multi-line code blocks from the current Antigravity conversation",
21
+ "strategy": "ui",
22
+ "browser": true,
23
+ "args": [],
24
+ "type": "ts",
25
+ "modulePath": "antigravity/extract-code.js",
26
+ "domain": "localhost",
27
+ "columns": [
28
+ "code"
29
+ ]
30
+ },
31
+ {
32
+ "site": "antigravity",
33
+ "name": "model",
34
+ "description": "Switch the active LLM model in Antigravity",
35
+ "strategy": "ui",
36
+ "browser": true,
37
+ "args": [
38
+ {
39
+ "name": "name",
40
+ "type": "str",
41
+ "required": true,
42
+ "positional": true,
43
+ "help": "Target model name (e.g. claude, gemini, o1)"
44
+ }
45
+ ],
46
+ "type": "ts",
47
+ "modulePath": "antigravity/model.js",
48
+ "domain": "localhost",
49
+ "columns": [
50
+ "status"
51
+ ]
52
+ },
53
+ {
54
+ "site": "antigravity",
55
+ "name": "new",
56
+ "description": "Start a new conversation / clear context in Antigravity",
57
+ "strategy": "ui",
58
+ "browser": true,
59
+ "args": [],
60
+ "type": "ts",
61
+ "modulePath": "antigravity/new.js",
62
+ "domain": "localhost",
63
+ "columns": [
64
+ "status"
65
+ ]
66
+ },
67
+ {
68
+ "site": "antigravity",
69
+ "name": "read",
70
+ "description": "Read the latest chat messages from Antigravity AI",
71
+ "strategy": "ui",
72
+ "browser": true,
73
+ "args": [
74
+ {
75
+ "name": "last",
76
+ "type": "str",
77
+ "required": false,
78
+ "help": "Number of recent messages to read (not fully implemented due to generic structure, currently returns full history text or latest chunk)"
79
+ }
80
+ ],
81
+ "type": "ts",
82
+ "modulePath": "antigravity/read.js",
83
+ "domain": "localhost",
84
+ "columns": [
85
+ "role",
86
+ "content"
87
+ ]
88
+ },
89
+ {
90
+ "site": "antigravity",
91
+ "name": "send",
92
+ "description": "Send a message to Antigravity AI via the internal Lexical editor",
93
+ "strategy": "ui",
94
+ "browser": true,
95
+ "args": [
96
+ {
97
+ "name": "message",
98
+ "type": "str",
99
+ "required": true,
100
+ "positional": true,
101
+ "help": "The message text to send"
102
+ }
103
+ ],
104
+ "type": "ts",
105
+ "modulePath": "antigravity/send.js",
106
+ "domain": "localhost",
107
+ "columns": [
108
+ "status",
109
+ "message"
110
+ ]
111
+ },
112
+ {
113
+ "site": "antigravity",
114
+ "name": "status",
115
+ "description": "Check Antigravity CDP connection and get current page state",
116
+ "strategy": "ui",
117
+ "browser": true,
118
+ "args": [],
119
+ "type": "ts",
120
+ "modulePath": "antigravity/status.js",
121
+ "domain": "localhost",
122
+ "columns": [
123
+ "status",
124
+ "url",
125
+ "title"
126
+ ]
127
+ },
128
+ {
129
+ "site": "antigravity",
130
+ "name": "watch",
131
+ "description": "Stream new chat messages from Antigravity in real-time",
132
+ "strategy": "ui",
133
+ "browser": true,
134
+ "args": [],
135
+ "type": "ts",
136
+ "modulePath": "antigravity/watch.js",
137
+ "domain": "localhost",
138
+ "columns": []
139
+ },
2
140
  {
3
141
  "site": "barchart",
4
142
  "name": "flow",
@@ -672,6 +810,103 @@
672
810
  "url"
673
811
  ]
674
812
  },
813
+ {
814
+ "site": "codex",
815
+ "name": "dump",
816
+ "description": "Dump the DOM and Accessibility tree of Codex for reverse-engineering",
817
+ "strategy": "ui",
818
+ "browser": true,
819
+ "args": [],
820
+ "type": "ts",
821
+ "modulePath": "codex/dump.js",
822
+ "domain": "localhost",
823
+ "columns": [
824
+ "action",
825
+ "files"
826
+ ]
827
+ },
828
+ {
829
+ "site": "codex",
830
+ "name": "extract-diff",
831
+ "description": "Extract visual code review diff patches from Codex",
832
+ "strategy": "ui",
833
+ "browser": true,
834
+ "args": [],
835
+ "type": "ts",
836
+ "modulePath": "codex/extract-diff.js",
837
+ "domain": "localhost",
838
+ "columns": [
839
+ "File",
840
+ "Diff"
841
+ ]
842
+ },
843
+ {
844
+ "site": "codex",
845
+ "name": "new",
846
+ "description": "Start a new Codex conversation thread / isolated workspace",
847
+ "strategy": "ui",
848
+ "browser": true,
849
+ "args": [],
850
+ "type": "ts",
851
+ "modulePath": "codex/new.js",
852
+ "domain": "localhost",
853
+ "columns": [
854
+ "Status",
855
+ "Action"
856
+ ]
857
+ },
858
+ {
859
+ "site": "codex",
860
+ "name": "read",
861
+ "description": "Read the contents of the current Codex conversation thread",
862
+ "strategy": "ui",
863
+ "browser": true,
864
+ "args": [],
865
+ "type": "ts",
866
+ "modulePath": "codex/read.js",
867
+ "domain": "localhost",
868
+ "columns": [
869
+ "Thread_Content"
870
+ ]
871
+ },
872
+ {
873
+ "site": "codex",
874
+ "name": "send",
875
+ "description": "Send text/commands to the Codex AI composer",
876
+ "strategy": "ui",
877
+ "browser": true,
878
+ "args": [
879
+ {
880
+ "name": "text",
881
+ "type": "str",
882
+ "required": true,
883
+ "help": "Text, command (e.g. /review), or skill (e.g. $imagegen)"
884
+ }
885
+ ],
886
+ "type": "ts",
887
+ "modulePath": "codex/send.js",
888
+ "domain": "localhost",
889
+ "columns": [
890
+ "Status",
891
+ "InjectedText"
892
+ ]
893
+ },
894
+ {
895
+ "site": "codex",
896
+ "name": "status",
897
+ "description": "Check active CDP connection to OpenAI Codex App",
898
+ "strategy": "ui",
899
+ "browser": true,
900
+ "args": [],
901
+ "type": "ts",
902
+ "modulePath": "codex/status.js",
903
+ "domain": "localhost",
904
+ "columns": [
905
+ "Status",
906
+ "Url",
907
+ "Title"
908
+ ]
909
+ },
675
910
  {
676
911
  "site": "coupang",
677
912
  "name": "add-to-cart",
@@ -2522,6 +2757,114 @@
2522
2757
  "url"
2523
2758
  ]
2524
2759
  },
2760
+ {
2761
+ "site": "xiaoyuzhou",
2762
+ "name": "episode",
2763
+ "description": "View details of a Xiaoyuzhou podcast episode",
2764
+ "strategy": "public",
2765
+ "browser": false,
2766
+ "args": [
2767
+ {
2768
+ "name": "id",
2769
+ "type": "str",
2770
+ "required": true,
2771
+ "positional": true,
2772
+ "help": "Episode ID (eid from podcast-episodes output)"
2773
+ }
2774
+ ],
2775
+ "type": "ts",
2776
+ "modulePath": "xiaoyuzhou/episode.js",
2777
+ "domain": "www.xiaoyuzhoufm.com",
2778
+ "columns": [
2779
+ "title",
2780
+ "podcast",
2781
+ "duration",
2782
+ "plays",
2783
+ "comments",
2784
+ "likes",
2785
+ "date"
2786
+ ]
2787
+ },
2788
+ {
2789
+ "site": "xiaoyuzhou",
2790
+ "name": "podcast-episodes",
2791
+ "description": "List recent episodes of a Xiaoyuzhou podcast (up to 15, SSR limit)",
2792
+ "strategy": "public",
2793
+ "browser": false,
2794
+ "args": [
2795
+ {
2796
+ "name": "id",
2797
+ "type": "str",
2798
+ "required": true,
2799
+ "positional": true,
2800
+ "help": "Podcast ID (from xiaoyuzhoufm.com URL)"
2801
+ },
2802
+ {
2803
+ "name": "limit",
2804
+ "type": "int",
2805
+ "default": 15,
2806
+ "required": false,
2807
+ "help": "Max episodes to show (up to 15, SSR limit)"
2808
+ }
2809
+ ],
2810
+ "type": "ts",
2811
+ "modulePath": "xiaoyuzhou/podcast-episodes.js",
2812
+ "domain": "www.xiaoyuzhoufm.com",
2813
+ "columns": [
2814
+ "eid",
2815
+ "title",
2816
+ "duration",
2817
+ "plays",
2818
+ "date"
2819
+ ]
2820
+ },
2821
+ {
2822
+ "site": "xiaoyuzhou",
2823
+ "name": "podcast",
2824
+ "description": "View a Xiaoyuzhou podcast profile",
2825
+ "strategy": "public",
2826
+ "browser": false,
2827
+ "args": [
2828
+ {
2829
+ "name": "id",
2830
+ "type": "str",
2831
+ "required": true,
2832
+ "positional": true,
2833
+ "help": "Podcast ID (from xiaoyuzhoufm.com URL)"
2834
+ }
2835
+ ],
2836
+ "type": "ts",
2837
+ "modulePath": "xiaoyuzhou/podcast.js",
2838
+ "domain": "www.xiaoyuzhoufm.com",
2839
+ "columns": [
2840
+ "title",
2841
+ "author",
2842
+ "description",
2843
+ "subscribers",
2844
+ "episodes",
2845
+ "updated"
2846
+ ]
2847
+ },
2848
+ {
2849
+ "site": "xiaoyuzhou",
2850
+ "name": "utils",
2851
+ "description": "",
2852
+ "strategy": "cookie",
2853
+ "browser": true,
2854
+ "args": [],
2855
+ "type": "ts",
2856
+ "modulePath": "xiaoyuzhou/utils.js"
2857
+ },
2858
+ {
2859
+ "site": "xiaoyuzhou",
2860
+ "name": "utils.test",
2861
+ "description": "",
2862
+ "strategy": "cookie",
2863
+ "browser": true,
2864
+ "args": [],
2865
+ "type": "ts",
2866
+ "modulePath": "xiaoyuzhou/utils.test.js"
2867
+ },
2525
2868
  {
2526
2869
  "site": "xueqiu",
2527
2870
  "name": "feed",
@@ -0,0 +1 @@
1
+ export declare const dumpCommand: import("../../registry.js").CliCommand;
@@ -0,0 +1,28 @@
1
+ import { cli, Strategy } from '../../registry.js';
2
+ import * as fs from 'node:fs';
3
+ export const dumpCommand = cli({
4
+ site: 'antigravity',
5
+ name: 'dump',
6
+ description: 'Dump the DOM to help AI understand the UI',
7
+ domain: 'localhost',
8
+ strategy: Strategy.UI,
9
+ browser: true,
10
+ args: [],
11
+ columns: ['htmlFile', 'snapFile'],
12
+ func: async (page) => {
13
+ // Extract HTML
14
+ const html = await page.evaluate('document.body.innerHTML');
15
+ fs.writeFileSync('/tmp/antigravity-dom.html', html);
16
+ // Extract Snapshot
17
+ let snapFile = '';
18
+ try {
19
+ const snap = await page.snapshot({ raw: true });
20
+ snapFile = '/tmp/antigravity-snapshot.json';
21
+ fs.writeFileSync(snapFile, JSON.stringify(snap, null, 2));
22
+ }
23
+ catch (e) {
24
+ snapFile = 'Failed';
25
+ }
26
+ return [{ htmlFile: '/tmp/antigravity-dom.html', snapFile }];
27
+ },
28
+ });
@@ -0,0 +1 @@
1
+ export declare const extractCodeCommand: import("../../registry.js").CliCommand;
@@ -0,0 +1,32 @@
1
+ import { cli, Strategy } from '../../registry.js';
2
+ export const extractCodeCommand = cli({
3
+ site: 'antigravity',
4
+ name: 'extract-code',
5
+ description: 'Extract multi-line code blocks from the current Antigravity conversation',
6
+ domain: 'localhost',
7
+ strategy: Strategy.UI,
8
+ browser: true,
9
+ args: [],
10
+ columns: ['code'],
11
+ func: async (page) => {
12
+ const blocks = await page.evaluate(`
13
+ async () => {
14
+ // Find standard pre/code blocks
15
+ let elements = Array.from(document.querySelectorAll('pre code'));
16
+
17
+ // Fallback to Monaco editor content inside the UI
18
+ if (elements.length === 0) {
19
+ elements = Array.from(document.querySelectorAll('.monaco-editor'));
20
+ }
21
+
22
+ // Generic fallback to any code tag that spans multiple lines
23
+ if (elements.length === 0) {
24
+ elements = Array.from(document.querySelectorAll('code')).filter(c => c.innerText.includes('\\n'));
25
+ }
26
+
27
+ return elements.map(el => el.innerText).filter(text => text.trim().length > 0);
28
+ }
29
+ `);
30
+ return blocks.map((code) => ({ code }));
31
+ },
32
+ });
@@ -0,0 +1 @@
1
+ export declare const modelCommand: import("../../registry.js").CliCommand;
@@ -0,0 +1,44 @@
1
+ import { cli, Strategy } from '../../registry.js';
2
+ export const modelCommand = cli({
3
+ site: 'antigravity',
4
+ name: 'model',
5
+ description: 'Switch the active LLM model in Antigravity',
6
+ domain: 'localhost',
7
+ strategy: Strategy.UI,
8
+ browser: true,
9
+ args: [
10
+ { name: 'name', help: 'Target model name (e.g. claude, gemini, o1)', required: true, positional: true }
11
+ ],
12
+ columns: ['status'],
13
+ func: async (page, kwargs) => {
14
+ const targetName = kwargs.name.toLowerCase();
15
+ await page.evaluate(`
16
+ async () => {
17
+ const targetModelName = ${JSON.stringify(targetName)};
18
+
19
+ // 1. Locate the model selector dropdown trigger
20
+ const trigger = document.querySelector('div[aria-haspopup="dialog"] > div[tabindex="0"]');
21
+ if (!trigger) throw new Error('Could not find the model selector trigger in the UI');
22
+ trigger.click();
23
+
24
+ // 2. Wait a brief moment for React to mount the Portal/Dialog
25
+ await new Promise(r => setTimeout(r, 200));
26
+
27
+ // 3. Find the option spanning target text
28
+ const spans = Array.from(document.querySelectorAll('[role="dialog"] span'));
29
+ const target = spans.find(s => s.innerText.toLowerCase().includes(targetModelName));
30
+ if (!target) {
31
+ // If not found, click the trigger again to close it safely
32
+ trigger.click();
33
+ throw new Error('Model matching "' + targetModelName + '" was not found in the dropdown list.');
34
+ }
35
+
36
+ // 4. Click the closest parent that handles the row action
37
+ const optionNode = target.closest('.cursor-pointer') || target;
38
+ optionNode.click();
39
+ }
40
+ `);
41
+ await page.wait(0.5);
42
+ return [{ status: `Model switched to: ${kwargs.name}` }];
43
+ },
44
+ });
@@ -0,0 +1 @@
1
+ export declare const newCommand: import("../../registry.js").CliCommand;
@@ -0,0 +1,25 @@
1
+ import { cli, Strategy } from '../../registry.js';
2
+ export const newCommand = cli({
3
+ site: 'antigravity',
4
+ name: 'new',
5
+ description: 'Start a new conversation / clear context in Antigravity',
6
+ domain: 'localhost',
7
+ strategy: Strategy.UI,
8
+ browser: true,
9
+ args: [],
10
+ columns: ['status'],
11
+ func: async (page) => {
12
+ await page.evaluate(`
13
+ async () => {
14
+ const btn = document.querySelector('[data-tooltip-id="new-conversation-tooltip"]');
15
+ if (!btn) throw new Error('Could not find New Conversation button');
16
+
17
+ // In case it's disabled, we must check, but we'll try to click it anyway
18
+ btn.click();
19
+ }
20
+ `);
21
+ // Give it a moment to reset the UI
22
+ await page.wait(0.5);
23
+ return [{ status: 'Successfully started a new conversation' }];
24
+ },
25
+ });
@@ -0,0 +1 @@
1
+ export declare const readCommand: import("../../registry.js").CliCommand;
@@ -0,0 +1,34 @@
1
+ import { cli, Strategy } from '../../registry.js';
2
+ export const readCommand = cli({
3
+ site: 'antigravity',
4
+ name: 'read',
5
+ description: 'Read the latest chat messages from Antigravity AI',
6
+ domain: 'localhost',
7
+ strategy: Strategy.UI,
8
+ browser: true,
9
+ args: [
10
+ { name: 'last', help: 'Number of recent messages to read (not fully implemented due to generic structure, currently returns full history text or latest chunk)' }
11
+ ],
12
+ columns: ['role', 'content'],
13
+ func: async (page, kwargs) => {
14
+ // We execute a script inside Antigravity's Chromium environment to extract the text
15
+ // of the entire conversation pane.
16
+ const rawText = await page.evaluate(`
17
+ async () => {
18
+ const container = document.getElementById('conversation');
19
+ if (!container) throw new Error('Could not find conversation container');
20
+
21
+ // Extract the full visible text of the conversation
22
+ // In Electron/Chromium, innerText preserves basic visual line breaks nicely
23
+ return container.innerText;
24
+ }
25
+ `);
26
+ // We can do simple heuristic parsing based on typical visual markers if needed.
27
+ // For now, we return the entire text blob, or just the last 2000 characters if it's too long.
28
+ const cleanText = String(rawText).trim();
29
+ return [{
30
+ role: 'history',
31
+ content: cleanText
32
+ }];
33
+ },
34
+ });
@@ -0,0 +1 @@
1
+ export declare const sendCommand: import("../../registry.js").CliCommand;