opencode-skills-collection 4.0.74 → 4.0.76
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/bundled-skills/.antigravity-install-manifest.json +16 -1
- package/bundled-skills/claude-api/SKILL.md +4 -4
- package/bundled-skills/claude-api/curl/examples.md +5 -5
- package/bundled-skills/claude-api/java/claude-api.md +1 -1
- package/bundled-skills/claude-api/php/claude-api.md +2 -2
- package/bundled-skills/claude-api/python/claude-api/README.md +13 -13
- package/bundled-skills/claude-api/python/claude-api/batches.md +3 -3
- package/bundled-skills/claude-api/python/claude-api/files-api.md +3 -3
- package/bundled-skills/claude-api/python/claude-api/streaming.md +6 -6
- package/bundled-skills/claude-api/python/claude-api/tool-use.md +19 -19
- package/bundled-skills/claude-api/ruby/claude-api.md +3 -3
- package/bundled-skills/claude-api/shared/error-codes.md +2 -2
- package/bundled-skills/claude-api/shared/live-sources.md +1 -1
- package/bundled-skills/claude-api/shared/models.md +4 -4
- package/bundled-skills/claude-api/shared/tool-use-concepts.md +2 -2
- package/bundled-skills/claude-api/typescript/claude-api/README.md +12 -12
- package/bundled-skills/claude-api/typescript/claude-api/batches.md +2 -2
- package/bundled-skills/claude-api/typescript/claude-api/files-api.md +1 -1
- package/bundled-skills/claude-api/typescript/claude-api/streaming.md +4 -4
- package/bundled-skills/claude-api/typescript/claude-api/tool-use.md +14 -14
- package/bundled-skills/electron-drive-skill/LICENSE +21 -0
- package/bundled-skills/electron-drive-skill/README.md +172 -0
- package/bundled-skills/electron-drive-skill/SKILL.md +237 -0
- package/bundled-skills/electron-drive-skill/drive.config.json.example +10 -0
- package/bundled-skills/electron-drive-skill/package.json +28 -0
- package/bundled-skills/electron-drive-skill/scripts/daemon.mjs +352 -0
- package/bundled-skills/electron-drive-skill/scripts/drive.mjs +250 -0
- package/bundled-skills/electron-drive-skill/scripts/lib.mjs +165 -0
- package/bundled-skills/electron-drive-skill/scripts/lib.test.mjs +56 -0
- package/bundled-skills/jev-social/SKILL.md +5 -5
- package/bundled-skills/lintlang-audit/SKILL.md +100 -0
- package/bundled-skills/mcp-dependency-drift-audit/SKILL.md +169 -0
- package/bundled-skills/nexrad-mosaic-access/SKILL.md +297 -0
- package/bundled-skills/nexrad-mosaic-construction/SKILL.md +277 -0
- package/bundled-skills/nexrad-product-access/SKILL.md +258 -0
- package/bundled-skills/nexrad-radar-visualization/SKILL.md +318 -0
- package/bundled-skills/radar-satellite-analysis/SKILL.md +314 -0
- package/bundled-skills/system-prompt-lookup/SKILL.md +188 -0
- package/bundled-skills/traderspy-market-briefing/SKILL.md +132 -0
- package/bundled-skills/traderspy-market-screener/SKILL.md +182 -0
- package/bundled-skills/traderspy-market-screener/references/condition-cookbook.md +70 -0
- package/bundled-skills/traderspy-position-check/SKILL.md +130 -0
- package/bundled-skills/traderspy-position-check/references/risk-math.md +60 -0
- package/bundled-skills/traderspy-smart-money/SKILL.md +151 -0
- package/bundled-skills/traderspy-smart-money/references/exchange-notes.md +40 -0
- package/bundled-skills/traderspy-technical-analysis/SKILL.md +162 -0
- package/bundled-skills/traderspy-technical-analysis/references/derivatives-guide.md +57 -0
- package/bundled-skills/traderspy-technical-analysis/references/indicator-guide.md +47 -0
- package/bundled-skills/traderspy-trading-signals/SKILL.md +156 -0
- package/bundled-skills/traderspy-trading-signals/references/signal-fields.md +64 -0
- package/bundled-skills/unified-ai-gateway/SKILL.md +58 -16
- package/package.json +1 -1
- package/skills_index.json +657 -358
|
@@ -24,7 +24,7 @@ const client = new Anthropic({ apiKey: "your-api-key" });
|
|
|
24
24
|
|
|
25
25
|
```typescript
|
|
26
26
|
const response = await client.messages.create({
|
|
27
|
-
model: "claude-opus-
|
|
27
|
+
model: "claude-opus-5",
|
|
28
28
|
max_tokens: 1024,
|
|
29
29
|
messages: [{ role: "user", content: "What is the capital of France?" }],
|
|
30
30
|
});
|
|
@@ -37,7 +37,7 @@ console.log(response.content[0].text);
|
|
|
37
37
|
|
|
38
38
|
```typescript
|
|
39
39
|
const response = await client.messages.create({
|
|
40
|
-
model: "claude-opus-
|
|
40
|
+
model: "claude-opus-5",
|
|
41
41
|
max_tokens: 1024,
|
|
42
42
|
system:
|
|
43
43
|
"You are a helpful coding assistant. Always provide examples in Python.",
|
|
@@ -53,7 +53,7 @@ const response = await client.messages.create({
|
|
|
53
53
|
|
|
54
54
|
```typescript
|
|
55
55
|
const response = await client.messages.create({
|
|
56
|
-
model: "claude-opus-
|
|
56
|
+
model: "claude-opus-5",
|
|
57
57
|
max_tokens: 1024,
|
|
58
58
|
messages: [
|
|
59
59
|
{
|
|
@@ -78,7 +78,7 @@ import fs from "fs";
|
|
|
78
78
|
const imageData = fs.readFileSync("image.png").toString("base64");
|
|
79
79
|
|
|
80
80
|
const response = await client.messages.create({
|
|
81
|
-
model: "claude-opus-
|
|
81
|
+
model: "claude-opus-5",
|
|
82
82
|
max_tokens: 1024,
|
|
83
83
|
messages: [
|
|
84
84
|
{
|
|
@@ -105,7 +105,7 @@ Use top-level `cache_control` to automatically cache the last cacheable block in
|
|
|
105
105
|
|
|
106
106
|
```typescript
|
|
107
107
|
const response = await client.messages.create({
|
|
108
|
-
model: "claude-opus-
|
|
108
|
+
model: "claude-opus-5",
|
|
109
109
|
max_tokens: 1024,
|
|
110
110
|
cache_control: { type: "ephemeral" }, // auto-caches the last cacheable block
|
|
111
111
|
system: "You are an expert on this large document...",
|
|
@@ -119,7 +119,7 @@ For fine-grained control, add `cache_control` to specific content blocks:
|
|
|
119
119
|
|
|
120
120
|
```typescript
|
|
121
121
|
const response = await client.messages.create({
|
|
122
|
-
model: "claude-opus-
|
|
122
|
+
model: "claude-opus-5",
|
|
123
123
|
max_tokens: 1024,
|
|
124
124
|
system: [
|
|
125
125
|
{
|
|
@@ -133,7 +133,7 @@ const response = await client.messages.create({
|
|
|
133
133
|
|
|
134
134
|
// With explicit TTL (time-to-live)
|
|
135
135
|
const response2 = await client.messages.create({
|
|
136
|
-
model: "claude-opus-
|
|
136
|
+
model: "claude-opus-5",
|
|
137
137
|
max_tokens: 1024,
|
|
138
138
|
system: [
|
|
139
139
|
{
|
|
@@ -156,7 +156,7 @@ const response2 = await client.messages.create({
|
|
|
156
156
|
```typescript
|
|
157
157
|
// Opus 4.6: adaptive thinking (recommended)
|
|
158
158
|
const response = await client.messages.create({
|
|
159
|
-
model: "claude-opus-
|
|
159
|
+
model: "claude-opus-5",
|
|
160
160
|
max_tokens: 16000,
|
|
161
161
|
thinking: { type: "adaptive" },
|
|
162
162
|
output_config: { effort: "high" }, // low | medium | high | max
|
|
@@ -214,7 +214,7 @@ const messages: Anthropic.MessageParam[] = [
|
|
|
214
214
|
];
|
|
215
215
|
|
|
216
216
|
const response = await client.messages.create({
|
|
217
|
-
model: "claude-opus-
|
|
217
|
+
model: "claude-opus-5",
|
|
218
218
|
max_tokens: 1024,
|
|
219
219
|
messages: messages,
|
|
220
220
|
});
|
|
@@ -243,7 +243,7 @@ async function chat(userMessage: string): Promise<string> {
|
|
|
243
243
|
|
|
244
244
|
const response = await client.beta.messages.create({
|
|
245
245
|
betas: ["compact-2026-01-12"],
|
|
246
|
-
model: "claude-opus-
|
|
246
|
+
model: "claude-opus-5",
|
|
247
247
|
max_tokens: 4096,
|
|
248
248
|
messages,
|
|
249
249
|
context_management: {
|
|
@@ -288,7 +288,7 @@ The `stop_reason` field in the response indicates why the model stopped generati
|
|
|
288
288
|
```typescript
|
|
289
289
|
// Automatic caching (simplest — caches the last cacheable block)
|
|
290
290
|
const response = await client.messages.create({
|
|
291
|
-
model: "claude-opus-
|
|
291
|
+
model: "claude-opus-5",
|
|
292
292
|
max_tokens: 1024,
|
|
293
293
|
cache_control: { type: "ephemeral" },
|
|
294
294
|
system: largeDocumentText, // e.g., 50KB of context
|
|
@@ -303,7 +303,7 @@ const response = await client.messages.create({
|
|
|
303
303
|
|
|
304
304
|
```typescript
|
|
305
305
|
const countResponse = await client.messages.countTokens({
|
|
306
|
-
model: "claude-opus-
|
|
306
|
+
model: "claude-opus-5",
|
|
307
307
|
messages: messages,
|
|
308
308
|
system: system,
|
|
309
309
|
});
|
|
@@ -24,7 +24,7 @@ const messageBatch = await client.messages.batches.create({
|
|
|
24
24
|
{
|
|
25
25
|
custom_id: "request-1",
|
|
26
26
|
params: {
|
|
27
|
-
model: "claude-opus-
|
|
27
|
+
model: "claude-opus-5",
|
|
28
28
|
max_tokens: 1024,
|
|
29
29
|
messages: [
|
|
30
30
|
{ role: "user", content: "Summarize climate change impacts" },
|
|
@@ -34,7 +34,7 @@ const messageBatch = await client.messages.batches.create({
|
|
|
34
34
|
{
|
|
35
35
|
custom_id: "request-2",
|
|
36
36
|
params: {
|
|
37
|
-
model: "claude-opus-
|
|
37
|
+
model: "claude-opus-5",
|
|
38
38
|
max_tokens: 1024,
|
|
39
39
|
messages: [
|
|
40
40
|
{ role: "user", content: "Explain quantum computing basics" },
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
6
|
const stream = client.messages.stream({
|
|
7
|
-
model: "claude-opus-
|
|
7
|
+
model: "claude-opus-5",
|
|
8
8
|
max_tokens: 1024,
|
|
9
9
|
messages: [{ role: "user", content: "Write a story" }],
|
|
10
10
|
});
|
|
@@ -27,7 +27,7 @@ for await (const event of stream) {
|
|
|
27
27
|
|
|
28
28
|
```typescript
|
|
29
29
|
const stream = client.messages.stream({
|
|
30
|
-
model: "claude-opus-
|
|
30
|
+
model: "claude-opus-5",
|
|
31
31
|
max_tokens: 16000,
|
|
32
32
|
thinking: { type: "adaptive" },
|
|
33
33
|
messages: [{ role: "user", content: "Analyze this problem" }],
|
|
@@ -82,7 +82,7 @@ const getWeather = betaZodTool({
|
|
|
82
82
|
});
|
|
83
83
|
|
|
84
84
|
const runner = client.beta.messages.toolRunner({
|
|
85
|
-
model: "claude-opus-
|
|
85
|
+
model: "claude-opus-5",
|
|
86
86
|
max_tokens: 4096,
|
|
87
87
|
tools: [getWeather],
|
|
88
88
|
messages: [
|
|
@@ -117,7 +117,7 @@ for await (const messageStream of runner) {
|
|
|
117
117
|
|
|
118
118
|
```typescript
|
|
119
119
|
const stream = client.messages.stream({
|
|
120
|
-
model: "claude-opus-
|
|
120
|
+
model: "claude-opus-5",
|
|
121
121
|
max_tokens: 1024,
|
|
122
122
|
messages: [{ role: "user", content: "Hello" }],
|
|
123
123
|
});
|
|
@@ -30,7 +30,7 @@ const getWeather = betaZodTool({
|
|
|
30
30
|
|
|
31
31
|
// The tool runner handles the agentic loop and returns the final message
|
|
32
32
|
const finalMessage = await client.beta.messages.toolRunner({
|
|
33
|
-
model: "claude-opus-
|
|
33
|
+
model: "claude-opus-5",
|
|
34
34
|
max_tokens: 4096,
|
|
35
35
|
tools: [getWeather],
|
|
36
36
|
messages: [{ role: "user", content: "What's the weather in Paris?" }],
|
|
@@ -61,7 +61,7 @@ let messages: Anthropic.MessageParam[] = [{ role: "user", content: userInput }];
|
|
|
61
61
|
|
|
62
62
|
while (true) {
|
|
63
63
|
const response = await client.messages.create({
|
|
64
|
-
model: "claude-opus-
|
|
64
|
+
model: "claude-opus-5",
|
|
65
65
|
max_tokens: 4096,
|
|
66
66
|
tools: tools,
|
|
67
67
|
messages: messages,
|
|
@@ -111,7 +111,7 @@ let messages: Anthropic.MessageParam[] = [{ role: "user", content: userInput }];
|
|
|
111
111
|
|
|
112
112
|
while (true) {
|
|
113
113
|
const stream = client.messages.stream({
|
|
114
|
-
model: "claude-opus-
|
|
114
|
+
model: "claude-opus-5",
|
|
115
115
|
max_tokens: 4096,
|
|
116
116
|
tools,
|
|
117
117
|
messages,
|
|
@@ -169,7 +169,7 @@ while (true) {
|
|
|
169
169
|
|
|
170
170
|
```typescript
|
|
171
171
|
const response = await client.messages.create({
|
|
172
|
-
model: "claude-opus-
|
|
172
|
+
model: "claude-opus-5",
|
|
173
173
|
max_tokens: 1024,
|
|
174
174
|
tools: tools,
|
|
175
175
|
messages: [{ role: "user", content: "What's the weather in Paris?" }],
|
|
@@ -180,7 +180,7 @@ for (const block of response.content) {
|
|
|
180
180
|
const result = await executeTool(block.name, block.input);
|
|
181
181
|
|
|
182
182
|
const followup = await client.messages.create({
|
|
183
|
-
model: "claude-opus-
|
|
183
|
+
model: "claude-opus-5",
|
|
184
184
|
max_tokens: 1024,
|
|
185
185
|
tools: tools,
|
|
186
186
|
messages: [
|
|
@@ -204,7 +204,7 @@ for (const block of response.content) {
|
|
|
204
204
|
|
|
205
205
|
```typescript
|
|
206
206
|
const response = await client.messages.create({
|
|
207
|
-
model: "claude-opus-
|
|
207
|
+
model: "claude-opus-5",
|
|
208
208
|
max_tokens: 1024,
|
|
209
209
|
tools: tools,
|
|
210
210
|
tool_choice: { type: "tool", name: "get_weather" },
|
|
@@ -224,7 +224,7 @@ import Anthropic from "@anthropic-ai/sdk";
|
|
|
224
224
|
const client = new Anthropic();
|
|
225
225
|
|
|
226
226
|
const response = await client.messages.create({
|
|
227
|
-
model: "claude-opus-
|
|
227
|
+
model: "claude-opus-5",
|
|
228
228
|
max_tokens: 4096,
|
|
229
229
|
messages: [
|
|
230
230
|
{
|
|
@@ -257,7 +257,7 @@ const uploaded = await client.beta.files.upload({
|
|
|
257
257
|
// Code execution is GA; Files API is still beta (pass via RequestOptions)
|
|
258
258
|
const response = await client.messages.create(
|
|
259
259
|
{
|
|
260
|
-
model: "claude-opus-
|
|
260
|
+
model: "claude-opus-5",
|
|
261
261
|
max_tokens: 4096,
|
|
262
262
|
messages: [
|
|
263
263
|
{
|
|
@@ -317,7 +317,7 @@ for (const block of response.content) {
|
|
|
317
317
|
```typescript
|
|
318
318
|
// First request: set up environment
|
|
319
319
|
const response1 = await client.messages.create({
|
|
320
|
-
model: "claude-opus-
|
|
320
|
+
model: "claude-opus-5",
|
|
321
321
|
max_tokens: 4096,
|
|
322
322
|
messages: [
|
|
323
323
|
{
|
|
@@ -333,7 +333,7 @@ const containerId = response1.container.id;
|
|
|
333
333
|
|
|
334
334
|
const response2 = await client.messages.create({
|
|
335
335
|
container: containerId,
|
|
336
|
-
model: "claude-opus-
|
|
336
|
+
model: "claude-opus-5",
|
|
337
337
|
max_tokens: 4096,
|
|
338
338
|
messages: [
|
|
339
339
|
{
|
|
@@ -353,7 +353,7 @@ const response2 = await client.messages.create({
|
|
|
353
353
|
|
|
354
354
|
```typescript
|
|
355
355
|
const response = await client.messages.create({
|
|
356
|
-
model: "claude-opus-
|
|
356
|
+
model: "claude-opus-5",
|
|
357
357
|
max_tokens: 2048,
|
|
358
358
|
messages: [
|
|
359
359
|
{
|
|
@@ -387,7 +387,7 @@ const handlers: MemoryToolHandlers = {
|
|
|
387
387
|
const memory = betaMemoryTool(handlers);
|
|
388
388
|
|
|
389
389
|
const runner = client.beta.messages.toolRunner({
|
|
390
|
-
model: "claude-opus-
|
|
390
|
+
model: "claude-opus-5",
|
|
391
391
|
max_tokens: 2048,
|
|
392
392
|
tools: [memory],
|
|
393
393
|
messages: [{ role: "user", content: "Remember my preferences" }],
|
|
@@ -424,7 +424,7 @@ const ContactInfoSchema = z.object({
|
|
|
424
424
|
const client = new Anthropic();
|
|
425
425
|
|
|
426
426
|
const response = await client.messages.parse({
|
|
427
|
-
model: "claude-opus-
|
|
427
|
+
model: "claude-opus-5",
|
|
428
428
|
max_tokens: 1024,
|
|
429
429
|
messages: [
|
|
430
430
|
{
|
|
@@ -445,7 +445,7 @@ console.log(response.parsed_output.name); // "Jane Doe"
|
|
|
445
445
|
|
|
446
446
|
```typescript
|
|
447
447
|
const response = await client.messages.create({
|
|
448
|
-
model: "claude-opus-
|
|
448
|
+
model: "claude-opus-5",
|
|
449
449
|
max_tokens: 1024,
|
|
450
450
|
messages: [
|
|
451
451
|
{
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Search 3D, LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# electron-drive-skill
|
|
2
|
+
|
|
3
|
+
An agentic skill that lets an agent drive
|
|
4
|
+
your Electron app the way a person would: start and stop it, read the screen,
|
|
5
|
+
click, type, take screenshots, run code in the renderer or main process, and
|
|
6
|
+
read logs. The agent can then check a UI change or reproduce a bug in the
|
|
7
|
+
real app, not just in unit tests.
|
|
8
|
+
|
|
9
|
+
|Tested On|Status|
|
|
10
|
+
|--|--|
|
|
11
|
+
|Claude Code|y|
|
|
12
|
+
|Muse Code|y|
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
$ drive start --build
|
|
16
|
+
Using the build from 0 minute(s) ago. Pass --build to rebuild.
|
|
17
|
+
{ "mode": "built", "profile": "default", "running": true, "window": { "title": "My App", ... } }
|
|
18
|
+
$ drive snapshot
|
|
19
|
+
- button "Get started"
|
|
20
|
+
$ drive click 'role=button[name="Get started"]'
|
|
21
|
+
clicked role=button[name="Get started"]
|
|
22
|
+
$ drive stop
|
|
23
|
+
quit via app.quit()
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The app runs under Playwright in a background daemon, so each command is a
|
|
27
|
+
separate, fast shell call. Every launch uses a scratch profile
|
|
28
|
+
(`--user-data-dir` under your temp directory), so the agent never touches your
|
|
29
|
+
real app data.
|
|
30
|
+
|
|
31
|
+
## Requirements
|
|
32
|
+
|
|
33
|
+
- Node.js 18 or later
|
|
34
|
+
- `electron` and `playwright-core` 1.49 or later, installed in your project:
|
|
35
|
+
```bash
|
|
36
|
+
npm i -D playwright-core
|
|
37
|
+
```
|
|
38
|
+
No browsers need to be downloaded; the driver uses your project's Electron.
|
|
39
|
+
- macOS or Linux. On Windows, run it as `node scripts/drive.mjs`. The
|
|
40
|
+
process-tree kill that `stop` falls back to is not implemented there.
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
Clone it into your project's skills directory:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
git clone https://github.com/Search-3D/electron-drive-skill .claude/skills/electron-drive-skill
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Or clone it into `~/.claude/skills/electron-drive-skill` to use it in every
|
|
51
|
+
project. The driver always uses the Electron and Playwright of the project you
|
|
52
|
+
run it in. Keep the folder name: it must match the `name` in `SKILL.md`.
|
|
53
|
+
|
|
54
|
+
The examples here call it `drive`. Nothing installs that command; to run it by
|
|
55
|
+
hand, add an alias:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
alias drive="node .claude/skills/electron-drive-skill/scripts/drive.mjs"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
> [!IMPORTANT]
|
|
62
|
+
> Make sure you have installed playwright in your project's developer dependencies, as outlined in the steps above.
|
|
63
|
+
|
|
64
|
+
## Configure
|
|
65
|
+
|
|
66
|
+
With no configuration, `start` runs `electron .` on whatever is already built.
|
|
67
|
+
For anything else, add `drive.config.json` at your project root (copy
|
|
68
|
+
[`drive.config.json.example`](drive.config.json.example) as a starting point).
|
|
69
|
+
Every field is optional:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"build": "npm run build",
|
|
74
|
+
"args": ["."],
|
|
75
|
+
"env": { "APP_DATA_DIR": "{profile}/data" },
|
|
76
|
+
"logFile": "logs/main.log",
|
|
77
|
+
"dev": {
|
|
78
|
+
"args": ["."],
|
|
79
|
+
"env": { "ELECTRON_RENDERER_URL": "http://localhost:5173" },
|
|
80
|
+
"url": "http://localhost:5173"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
| Field | Meaning |
|
|
86
|
+
|---|---|
|
|
87
|
+
| `build` | Shell command that `start --build` runs first. |
|
|
88
|
+
| `args` | Arguments to Electron: the app directory (its `package.json` `main` must be the built entry point) or the entry file. For example, electron-react-boilerplate uses `["release/app"]`. |
|
|
89
|
+
| `env` | Added to the app's environment. `{profile}` becomes the scratch profile directory; it is replaced only in `env` values, not in `args`. Use it to redirect any data the app keeps outside `userData` (see below). |
|
|
90
|
+
| `logFile` | A log file, relative to the profile directory, that `logs` shows along with the console output. |
|
|
91
|
+
| `dev.args`, `dev.env` | Used by `start --dev` instead of `args` (plus `env`). |
|
|
92
|
+
| `dev.url` | The renderer dev server. `start --dev` refuses to launch if it is not up. |
|
|
93
|
+
|
|
94
|
+
### Redirecting app data with `env`
|
|
95
|
+
|
|
96
|
+
Every launch gets `--user-data-dir` pointed at a scratch profile, which moves
|
|
97
|
+
`app.getPath('userData')` and everything Electron stores there. Data your app
|
|
98
|
+
keeps somewhere else, such as a database, a library folder or a cache path, is
|
|
99
|
+
**not** moved, so the agent would work on your real files.
|
|
100
|
+
|
|
101
|
+
If your app keeps data elsewhere, give it an environment variable that
|
|
102
|
+
overrides the location, and set that variable in `env`:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
// main process
|
|
106
|
+
const dataDir = process.env.APP_DATA_DIR ?? defaultDataDir()
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{ "env": { "APP_DATA_DIR": "{profile}/data" } }
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`APP_DATA_DIR` is only an example name. The driver just sets the variable, so
|
|
114
|
+
it has an effect only if your app reads it. Use whatever name your app
|
|
115
|
+
already checks.
|
|
116
|
+
|
|
117
|
+
For `--dev`, start your renderer dev server yourself, and make sure it does not
|
|
118
|
+
also launch Electron.
|
|
119
|
+
|
|
120
|
+
## Commands
|
|
121
|
+
|
|
122
|
+
```text
|
|
123
|
+
start [--dev] [--build] [--profile <name>] [--fresh]
|
|
124
|
+
status whether the app is up, its profile and window
|
|
125
|
+
snapshot accessibility tree of the window
|
|
126
|
+
screenshot [--out <png>] [--selector <css>]
|
|
127
|
+
click <target> Playwright selector: 'text=Settings', 'role=button[name="Save"]', css
|
|
128
|
+
fill <target> <text>
|
|
129
|
+
select <target> <value|label>
|
|
130
|
+
press <key> e.g. Enter, Escape, Control+K
|
|
131
|
+
wait <target> [--timeout <ms>]
|
|
132
|
+
eval <js | -> in the renderer; '-' reads stdin
|
|
133
|
+
main <js | -> in the main process; 'electron' and 'process' are in scope
|
|
134
|
+
logs [--lines <n>]
|
|
135
|
+
stop
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Put `--` before text that starts with dashes, so it is not read as a flag:
|
|
139
|
+
`drive fill 'role=textbox[name="Args"]' -- --verbose`.
|
|
140
|
+
|
|
141
|
+
`eval` and `main` return their result as JSON. A DOM node, a function or
|
|
142
|
+
anything else that does not serialize comes back as `undefined` or `{}`;
|
|
143
|
+
return plain data instead (`el.textContent`, not `el`).
|
|
144
|
+
|
|
145
|
+
Run the script directly instead of through a `yarn`/`npm` script alias. yarn 1
|
|
146
|
+
re-splits arguments and drops inner quotes, which silently breaks most
|
|
147
|
+
JavaScript passed to `eval` and `main`.
|
|
148
|
+
|
|
149
|
+
## Limitations
|
|
150
|
+
|
|
151
|
+
- **One window.** Commands act on the first window that is not DevTools.
|
|
152
|
+
There is no way to pick another one, so a settings window or a second
|
|
153
|
+
document window cannot be driven. An app with a splash screen is driven
|
|
154
|
+
once the splash closes and the main window is the only one left; check
|
|
155
|
+
`status` to see which window is current.
|
|
156
|
+
- **One app at a time** per project: `start` refuses while one is running.
|
|
157
|
+
- **Windows:** run it as `node scripts/drive.mjs`; the process-tree kill that
|
|
158
|
+
`stop` falls back to is POSIX only.
|
|
159
|
+
|
|
160
|
+
## How it works
|
|
161
|
+
|
|
162
|
+
- `scripts/drive.mjs`: the CLI. `start` spawns the daemon and waits for it.
|
|
163
|
+
Every other command is one HTTP request to it.
|
|
164
|
+
- `scripts/daemon.mjs`: launches Electron through Playwright's `_electron`
|
|
165
|
+
API and serves commands on `127.0.0.1` with a random token. Its state file
|
|
166
|
+
and log are in `$TMPDIR/electron-drive/<project>-<hash>/`.
|
|
167
|
+
- `scripts/lib.mjs`: config, argument parsing and paths, with no side
|
|
168
|
+
effects. Tests: `node --test scripts/`.
|
|
169
|
+
|
|
170
|
+
## License
|
|
171
|
+
|
|
172
|
+
[MIT](LICENSE)
|