webhelm 1.0.15 → 1.0.17

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 CHANGED
@@ -63,7 +63,7 @@ Keep platform-specific code and tests in `lalalic/webhelm-actions`. Runtime test
63
63
 
64
64
  ### Adding an unsupported platform
65
65
 
66
- The WebHelm Skill includes [`skills/webhelm/NEW_PLATFORM.md`](skills/webhelm/NEW_PLATFORM.md). All new platform code belongs in **`~/.local/webhelm/platforms/<slug>`**, checked out from `lalalic/webhelm-actions`, including tests and docs. There is no separate `platforms/` directory in the Skill or npm package. Publishing an Action uses Git, not npm.
66
+ The repository provides [`docs/NEW_PLATFORM.md`](docs/NEW_PLATFORM.md) for maintainers. All new platform code belongs in **`~/.local/webhelm/platforms/<slug>`**, checked out from `lalalic/webhelm-actions`, including tests and docs. There is no separate `platforms/` directory in the Skill or npm package. Publishing an Action uses Git, not npm.
67
67
 
68
68
  ## npm publishing
69
69
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webhelm",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "description": "Agent browser automation in a visible managed Chrome with persistent JavaScript sessions",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,7 +16,7 @@
16
16
  "PRIVACY.md"
17
17
  ],
18
18
  "scripts": {
19
- "test": "node --test test/node/*.test.mjs test/workspace-manager.test.mjs skills/webhelm/tests/*.test.mjs",
19
+ "test": "node --test test/node/*.test.mjs test/workspace-manager.test.mjs test/skill/*.test.mjs",
20
20
  "test:package": "npm pack --dry-run --json",
21
21
  "test:e2e:extension": "node test/e2e/extension-control.e2e.mjs"
22
22
  },
@@ -0,0 +1,322 @@
1
+ // CLI help is the single agent-facing command reference. Keep it in sync with
2
+ // the dispatcher's supported commands and flags.
3
+ const common = 'Use \`webhelm COMMAND --help\` or \`webhelm help COMMAND\` for detailed usage.';
4
+
5
+ const sections = {
6
+ '': `webhelm — operate managed Chrome through persistent browser Sessions and site Actions
7
+
8
+ Usage:
9
+ webhelm <command> [options]
10
+ webhelm help [command [subcommand]]
11
+
12
+ Commands:
13
+ webhelm setup Set up managed Chrome and local Actions
14
+ webhelm status Report browser and daemon status (JSON)
15
+ webhelm ensure Check and recover managed Chrome health
16
+ webhelm capacity Report available browser capacity (JSON)
17
+ webhelm session start [--url URL] Start a persistent browser Session
18
+ webhelm session list List CLI-owned Sessions
19
+ webhelm session exec ID [--code-file F] Run JavaScript in a Session
20
+ webhelm session heartbeat ID Keep a Session alive during idle waits
21
+ webhelm session stop ID|--all Stop a Session or explicitly stop all CLI Sessions
22
+ webhelm platform list List installed website integrations
23
+ webhelm platform profile NAME Inspect a site's supported fields
24
+ webhelm platform source NAME ACTION Read the source of an installed Action
25
+ webhelm platform run NAME ACTION [...] Execute an installed site Action
26
+ webhelm platform sync Update installed site Actions
27
+ webhelm platform publish --message MSG Publish reviewed site Action changes
28
+ webhelm migrate Migrate supported legacy local browser data
29
+ webhelm help [command [subcommand]] Show command help
30
+ Options:
31
+ -h, --help Show help without running the command
32
+
33
+ Output: operational commands emit JSON; platform source prints JavaScript source.
34
+ ${common}`,
35
+ help: `webhelm help — show command usage without side effects
36
+
37
+ Usage:
38
+ webhelm --help
39
+ webhelm help [COMMAND [SUBCOMMAND]]
40
+ webhelm COMMAND [SUBCOMMAND] --help
41
+
42
+ Shows all commands or detailed usage for any available command and subcommand.
43
+ Help never initializes Chrome, changes Sessions, or runs site Actions.
44
+
45
+ Example:
46
+ webhelm help session exec`,
47
+ setup: `webhelm setup — prepare local Actions and managed Chrome
48
+
49
+ Usage:
50
+ webhelm setup
51
+
52
+ Initializes or reuses the site Actions checkout, starts or reuses managed
53
+ Chrome and its daemon, and registers the login-time health check.
54
+ Does not replace an existing Actions checkout with local changes.
55
+ Output: JSON with status, Actions checkout path, daemon and browser details.
56
+
57
+ Example:
58
+ webhelm setup`,
59
+ status: `webhelm status — inspect managed browser and daemon
60
+
61
+ Usage:
62
+ webhelm status
63
+
64
+ Output: JSON describing CLI version, installed Actions location, managed
65
+ Chrome process and profile, health-check state, and daemon Session count.
66
+
67
+ Example:
68
+ webhelm status`,
69
+ ensure: `webhelm ensure — verify and recover managed Chrome health
70
+
71
+ Usage:
72
+ webhelm ensure
73
+
74
+ Checks the existing daemon and managed browser and attempts a safe recovery.
75
+ May defer an incompatible upgrade while active Sessions are running.
76
+ Output: JSON health or deferred-upgrade result.
77
+
78
+ Example:
79
+ webhelm ensure`,
80
+ capacity: `webhelm capacity — inspect browser availability
81
+
82
+ Usage:
83
+ webhelm capacity
84
+
85
+ Reports allocatable browser capacity without opening a Session.
86
+ Output: JSON capacity information.
87
+
88
+ Example:
89
+ webhelm capacity`,
90
+ migrate: `webhelm migrate — migrate supported legacy local browser data
91
+
92
+ Usage:
93
+ webhelm migrate
94
+
95
+ Run only after stopping the legacy daemon and browser and draining Sessions.
96
+ Preserves the signed-in browser profile and supported local state.
97
+ Output: JSON with migration results.
98
+
99
+ Example:
100
+ webhelm migrate`,
101
+ session: `webhelm session — manage persistent JavaScript browser Sessions
102
+
103
+ Usage:
104
+ webhelm session <subcommand> [options]
105
+
106
+ Subcommands:
107
+ start [--url URL] Start a Session and receive a session_id
108
+ list List active CLI-owned Sessions
109
+ exec ID [--code-file FILE] Run JavaScript in a persistent Session
110
+ heartbeat ID Refresh the idle timer for a Session
111
+ stop ID Stop one Session and release its tab
112
+ stop --all Stop all CLI-owned Sessions (destructive)
113
+
114
+ Always reuse the returned session_id; stop only Sessions owned by your task.
115
+ An idle Session can be reclaimed after five minutes without activity.
116
+ Long-running workflows should heartbeat at least every 60 seconds.
117
+
118
+ Examples:
119
+ webhelm session start --url https://example.com
120
+ webhelm session list
121
+ webhelm session exec SESSION_ID --code-file ./inspect.js
122
+ webhelm session stop SESSION_ID
123
+
124
+ Run 'webhelm session <subcommand> --help' for detailed usage.`,
125
+ 'session start': `webhelm session start — open a persistent browser Session
126
+
127
+ Usage:
128
+ webhelm session start [--url URL]
129
+
130
+ Options:
131
+ --url URL Optional initial http(s) destination
132
+ -h, --help Show help without opening a browser Session
133
+
134
+ Output: JSON containing the new session_id. Retain it for exec and stop.
135
+
136
+ Example:
137
+ webhelm session start --url https://example.com`,
138
+ 'session list': `webhelm session list — list CLI-owned Sessions
139
+
140
+ Usage:
141
+ webhelm session list
142
+
143
+ Output: JSON with session_count and sessions array, including session_id.
144
+ Does not create a Session.
145
+
146
+ Example:
147
+ webhelm session list`,
148
+ 'session exec': `webhelm session exec — run JavaScript in an existing Session
149
+
150
+ Usage:
151
+ webhelm session exec SESSION_ID [--code-file FILE]
152
+ webhelm session exec SESSION_ID <<'JS'
153
+ console.log(await snapshot());
154
+ JS
155
+
156
+ Arguments:
157
+ SESSION_ID ID returned by 'webhelm session start'
158
+
159
+ Options:
160
+ --code-file FILE Read JavaScript from FILE instead of standard input
161
+ -h, --help Show help without executing code
162
+
163
+ The JavaScript context persists across exec calls. Browser helpers are async:
164
+ snapshot, page_info, goto_url, wait_for_load, wait_for_element,
165
+ fill_input, click, js, cdp, new_tab, current_tab, list_tabs,
166
+ switch_tab, close_tab, upload_file, type_text, capture_screenshot,
167
+ wait.
168
+ Read 'snapshot()' before using element references and refresh after navigation.
169
+ Use 'new_tab()' rather than raw CDP target creation.
170
+ Output: JSON with execution status and captured result/stdout.
171
+
172
+ Example:
173
+ printf 'console.log(await page_info());\\n' | webhelm session exec SESSION_ID`,
174
+ 'session heartbeat': `webhelm session heartbeat — keep an active Session alive
175
+
176
+ Usage:
177
+ webhelm session heartbeat SESSION_ID
178
+
179
+ Refreshes the Session's idle timer without navigating or changing tabs.
180
+ Use at least every 60 seconds during long waits with no browser operations.
181
+ Output: JSON heartbeat result.
182
+
183
+ Example:
184
+ webhelm session heartbeat SESSION_ID`,
185
+ 'session stop': `webhelm session stop — release browser Sessions
186
+
187
+ Usage:
188
+ webhelm session stop SESSION_ID
189
+ webhelm session stop --all
190
+
191
+ Arguments:
192
+ SESSION_ID Release one Session owned by the current workflow
193
+
194
+ Options:
195
+ --all Stop every CLI-owned Session; use only when explicitly authorized
196
+ -h, --help Show help without stopping Sessions
197
+
198
+ Output: JSON release result. Stopping a Session may return its tab to idle.
199
+ Do not use --all for ordinary task cleanup.
200
+
201
+ Example:
202
+ webhelm session stop SESSION_ID`,
203
+ platform: `webhelm platform — use installed website Actions
204
+
205
+ Usage:
206
+ webhelm platform <subcommand> [options]
207
+
208
+ Subcommands:
209
+ list List installed site platforms
210
+ profile PLATFORM Report site fields and capabilities
211
+ source PLATFORM ACTION Print the Action's JavaScript source
212
+ run PLATFORM ACTION [opts] Execute a site Action in a browser Session
213
+ sync Fast-forward local Action definitions
214
+ publish --message MESSAGE Test, commit and push reviewed Action changes
215
+
216
+ Examples:
217
+ webhelm platform list
218
+ webhelm platform profile chatgpt
219
+ webhelm platform source z new-turn
220
+ webhelm platform run z new-turn --session-id SESSION_ID --config ./input.json
221
+
222
+ Run 'webhelm platform <subcommand> --help' for detailed usage.`,
223
+ 'platform list': `webhelm platform list — discover installed website platforms
224
+
225
+ Usage:
226
+ webhelm platform list
227
+
228
+ Output: JSON array of available site names, read from installed Actions.
229
+
230
+ Example:
231
+ webhelm platform list`,
232
+ 'platform profile': `webhelm platform profile — inspect a website integration
233
+
234
+ Usage:
235
+ webhelm platform profile PLATFORM
236
+
237
+ Arguments:
238
+ PLATFORM Site name from 'webhelm platform list'
239
+
240
+ Output: JSON profile with available capabilities, field schemas and notes
241
+ when declared by the platform. Read it before building Action input.
242
+
243
+ Example:
244
+ webhelm platform profile chatgpt`,
245
+ 'platform source': `webhelm platform source — inspect an installed site Action
246
+
247
+ Usage:
248
+ webhelm platform source PLATFORM ACTION
249
+
250
+ Arguments:
251
+ PLATFORM Site name from 'webhelm platform list'
252
+ ACTION Action name defined by the site's manifest
253
+
254
+ Output: JavaScript source text (not JSON). Inspection has no browser effect.
255
+
256
+ Example:
257
+ webhelm platform source z new-turn`,
258
+ 'platform run': `webhelm platform run — execute an installed site Action
259
+
260
+ Usage:
261
+ webhelm platform run PLATFORM ACTION --session-id SESSION_ID [--config FILE] [--url URL]
262
+ webhelm platform run PLATFORM ACTION --auto-session [--config FILE] [--url URL]
263
+ webhelm platform run chatgpt new-turn [--config FILE] [--mode async|sync] [--session-id ID]
264
+
265
+ Arguments:
266
+ PLATFORM Site name from 'webhelm platform list'
267
+ ACTION Action name declared by the site's manifest
268
+
269
+ Options:
270
+ --session-id ID Reuse a caller-owned Session (normal interactive mode)
271
+ --auto-session Create and release a Session for one self-contained Action
272
+ --config FILE Read a JSON object of Action-specific inputs (default: {})
273
+ --url URL Optional initial URL for a browser Action
274
+ --mode MODE Only for chatgpt/new-turn: async (default) or sync
275
+ -h, --help Show help without executing an Action
276
+
277
+ --session-id and --auto-session cannot be combined. For chatgpt/new-turn,
278
+ async mode uses no Session option; sync mode requires --session-id.
279
+ Inspect 'platform profile' and 'platform source' for Action-specific inputs.
280
+ Output: JSON Action result. An accepted submission may require later verification.
281
+
282
+ Examples:
283
+ webhelm platform run z new-turn --session-id SESSION_ID --config ./turn.json
284
+ webhelm platform run chatgpt new-turn --config ./turn.json
285
+ webhelm platform run chatgpt new-turn --mode sync --session-id SESSION_ID --config ./turn.json`,
286
+ 'platform sync': `webhelm platform sync — update installed site Actions
287
+
288
+ Usage:
289
+ webhelm platform sync
290
+
291
+ Fetches and fast-forwards the Actions checkout. Refuses to overwrite local
292
+ changes or a diverged checkout. Does not update the browser Runtime.
293
+ Output: JSON sync status and revision.
294
+
295
+ Example:
296
+ webhelm platform sync`,
297
+ 'platform publish': `webhelm platform publish — publish verified site Action changes
298
+
299
+ Usage:
300
+ webhelm platform publish --message "DESCRIPTION"
301
+
302
+ Options:
303
+ --message DESCRIPTION Required commit description (8–250 characters)
304
+ -h, --help Show help without publishing
305
+
306
+ Runs the independent Actions tests, stages site Action files, commits, and
307
+ pushes without force. Use only for reviewed, authorized changes. Do not
308
+ publish account data, secrets or browser traces.
309
+ Output: JSON publish status and revision.
310
+
311
+ Example:
312
+ webhelm platform publish --message "fix(z): update composer selector"`,
313
+ };
314
+
315
+ export const helpTopics = Object.freeze(Object.keys(sections).filter(Boolean));
316
+ export function cliHelp(topics=[]) {
317
+ const parts = topics.filter(Boolean);
318
+ const key = parts.length>1 && ['session','platform'].includes(parts[0])
319
+ ? parts.slice(0,2).join(' ') : (parts[0] || '');
320
+ if (!Object.hasOwn(sections,key)) throw Error(`unknown help topic: ${parts.join(' ')}`);
321
+ return sections[key];
322
+ }
package/runtime/cli.mjs CHANGED
@@ -9,6 +9,7 @@ import { PLATFORMS, listPlatforms, platformProfile, actionPath, validateConfig }
9
9
  import { ACTIONS_DIR, ensureActions, syncActions, publishActions } from './actions-repo.mjs';
10
10
  import { migrateConfig, migrateChromeProfile } from './migrate.mjs';
11
11
  import { installLoginGuard, stageRuntimeForLoginGuard } from './login-guard.mjs';
12
+ import { cliHelp } from './cli-help.mjs';
12
13
 
13
14
  const ROOT = path.dirname(fileURLToPath(import.meta.url));
14
15
  const CLI_WORKSPACE = 'WebHelm';
@@ -19,30 +20,6 @@ const arg = (items, name) => {
19
20
  };
20
21
  const has = (items, name) => items.includes(name);
21
22
 
22
- function help() {
23
- console.log(`webhelm — browser automation through one Node.js runtime
24
-
25
- Usage:
26
- webhelm migrate # after stopping Chrome and the old WebHelm daemon
27
- webhelm setup
28
- webhelm status
29
- webhelm ensure # verify/recover managed Chrome and WebHelm group, not just daemon ping
30
- webhelm capacity # WebHelm workspace only
31
- webhelm session start [--url URL] # WebHelm workspace only
32
- webhelm session list
33
- webhelm session heartbeat SESSION_ID # keep a working Session alive
34
- webhelm session exec SESSION_ID [--code-file FILE] # JavaScript
35
- webhelm session stop SESSION_ID|--all
36
- webhelm platform list
37
- webhelm platform sync
38
- webhelm platform publish --message "DESCRIPTION"
39
- webhelm platform profile PLATFORM
40
- webhelm platform source PLATFORM ACTION
41
- webhelm platform run PLATFORM ACTION [--session-id ID | --auto-session] [--config FILE] [--mode async|sync]
42
-
43
- Agent workflows should keep their session_id across browser actions and always stop owned sessions.
44
- `);
45
- }
46
23
 
47
24
  function loadConfig(args) {
48
25
  const file = arg(args, '--config');
@@ -118,7 +95,14 @@ async function requireCliSession(sessionId) {
118
95
 
119
96
  async function main(args = process.argv.slice(2)) {
120
97
  const [group, command] = args;
121
- if (!group || ['--help', '-h', 'help'].includes(group) || has(args, '--help') || has(args, '-h')) return help();
98
+ if (!group || ['--help', '-h', 'help'].includes(group) || has(args, '--help') || has(args, '-h') ||
99
+ ((group === 'session' || group === 'platform') && (!command || command === 'help'))) {
100
+ const topics = group === 'help'
101
+ ? args.slice(1).filter(item => !['--help', '-h'].includes(item))
102
+ : ['--help', '-h'].includes(group) ? [] : args.filter(item => !['--help', '-h', 'help'].includes(item));
103
+ if (group === 'help' && !topics.length && (has(args, '--help') || has(args, '-h'))) topics.push('help');
104
+ return console.log(cliHelp(topics));
105
+ }
122
106
  rejectWorkspaceOverride(args);
123
107
  if (group === 'migrate') {
124
108
  await ensureActions(); // ~/.local/webhelm is the Actions Git checkout, never create an empty replacement.
@@ -136,7 +120,20 @@ async function main(args = process.argv.slice(2)) {
136
120
  const login_guard=installLoginGuard({cliPath,nodePath:process.execPath,sourceMode});
137
121
  return emit({status:'ready',...repo,daemon_pid:chrome.pid,managed_chrome:chrome.managed_chrome,login_guard});
138
122
  }
139
- if (group === 'ensure') return emit(await request({op:'guard-check'}));
123
+ if (group === 'ensure') {
124
+ try { return emit(await request({op:'guard-check'})); }
125
+ catch(error) {
126
+ // An older, still-busy daemon can hold the same socket during a
127
+ // rolling source upgrade. Preserve its Sessions; never hot-swap it.
128
+ if (!String(error.message).includes('unknown op: guard-check')) throw error;
129
+ const legacy=await request({op:'ping'});
130
+ if (legacy.session_count>0)
131
+ return emit({ok:true,deferred_upgrade:true,reason:'legacy_daemon_has_active_sessions',
132
+ session_count:legacy.session_count,daemon_version:legacy.version||'unknown',
133
+ chrome_health:'not_verified'});
134
+ throw Error('Legacy WebHelm daemon lacks health guard; drain and migrate it before activating the new source Runtime');
135
+ }
136
+ }
140
137
  if (group === 'status') {
141
138
  const daemon = await ensureDaemon();
142
139
  return emit({version:daemon.version, platform_dir:PLATFORMS, root:ROOT,