@surething/cockpit 1.0.217 → 1.0.218

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 (63) hide show
  1. package/.next-prod/BUILD_ID +1 -1
  2. package/.next-prod/app-path-routes-manifest.json +3 -3
  3. package/.next-prod/build-manifest.json +2 -2
  4. package/.next-prod/prerender-manifest.json +3 -3
  5. package/.next-prod/server/app/_global-error/page_client-reference-manifest.js +1 -1
  6. package/.next-prod/server/app/_global-error.html +1 -1
  7. package/.next-prod/server/app/_global-error.rsc +1 -1
  8. package/.next-prod/server/app/_global-error.segments/_full.segment.rsc +1 -1
  9. package/.next-prod/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  10. package/.next-prod/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  11. package/.next-prod/server/app/_global-error.segments/_head.segment.rsc +1 -1
  12. package/.next-prod/server/app/_global-error.segments/_index.segment.rsc +1 -1
  13. package/.next-prod/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next-prod/server/app/_not-found/page_client-reference-manifest.js +1 -1
  15. package/.next-prod/server/app/_not-found.html +1 -1
  16. package/.next-prod/server/app/_not-found.rsc +3 -3
  17. package/.next-prod/server/app/_not-found.segments/_full.segment.rsc +3 -3
  18. package/.next-prod/server/app/_not-found.segments/_head.segment.rsc +1 -1
  19. package/.next-prod/server/app/_not-found.segments/_index.segment.rsc +3 -3
  20. package/.next-prod/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  21. package/.next-prod/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  22. package/.next-prod/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  23. package/.next-prod/server/app/api/chat/deepseek/route.js +1 -1
  24. package/.next-prod/server/app/api/chat/route.js +1 -1
  25. package/.next-prod/server/app/api/extension/version/route.js.nft.json +1 -1
  26. package/.next-prod/server/app/api/projectGraph/file-functions/route.js +1 -1
  27. package/.next-prod/server/app/api/scheduled-tasks/route.js +1 -1
  28. package/.next-prod/server/app/page_client-reference-manifest.js +1 -1
  29. package/.next-prod/server/app/project/page_client-reference-manifest.js +1 -1
  30. package/.next-prod/server/app/review/[id]/page_client-reference-manifest.js +1 -1
  31. package/.next-prod/server/app-paths-manifest.json +3 -3
  32. package/.next-prod/server/chunks/2939.js +1 -1
  33. package/.next-prod/server/chunks/8916.js +1 -1
  34. package/.next-prod/server/chunks/9658.js +5 -5
  35. package/.next-prod/server/middleware-build-manifest.js +1 -1
  36. package/.next-prod/server/pages/404.html +1 -1
  37. package/.next-prod/server/pages/500.html +1 -1
  38. package/.next-prod/server/server-reference-manifest.json +1 -1
  39. package/.next-prod/static/chunks/6345-2637497e8b101740.js +14 -0
  40. package/.next-prod/static/chunks/{6917-0a22d7764ca45244.js → 6917-ed0e9c62a123d529.js} +2 -2
  41. package/.next-prod/static/chunks/app/{layout-8e3a54b794cb35b6.js → layout-1659a95e6c4a6bb5.js} +1 -1
  42. package/.next-prod/static/chunks/app/{page-3ab0a0f28cbdc8e2.js → page-afcbd897b4c3600f.js} +1 -1
  43. package/.next-prod/static/chunks/app/project/{page-3ab0a0f28cbdc8e2.js → page-afcbd897b4c3600f.js} +1 -1
  44. package/.next-prod/static/css/f4a773117ca8af75.css +1 -0
  45. package/.next-prod/trace +13 -13
  46. package/.next-prod/trace-build +1 -1
  47. package/README.md +5 -5
  48. package/README.zh.md +5 -5
  49. package/bin/cock-browser.messages.mjs +176 -0
  50. package/bin/cock-browser.mjs +290 -18
  51. package/chrome-extension/automation.js +684 -32
  52. package/chrome-extension/manifest.json +1 -1
  53. package/chrome-extension/messages.js +45 -0
  54. package/dist/{chunk-W6G6X3FP.mjs → chunk-WOM47O75.mjs} +49 -1
  55. package/dist/httpApi.mjs +66 -6
  56. package/dist/scheduledTasks.mjs +6 -1
  57. package/dist/{server-ZBUZ24TC.mjs → server-SNB4H35J.mjs} +5 -1
  58. package/dist/wsServer.mjs +5 -2
  59. package/package.json +3 -5
  60. package/.next-prod/static/chunks/6345-d477b8d5c682b1fb.js +0 -14
  61. package/.next-prod/static/css/fc2730c2dbe4866e.css +0 -1
  62. /package/.next-prod/static/{7pu1LXbRRLfg05VN3u39s → bOkuiIr_nWzG5GjPLNqdN}/_buildManifest.js +0 -0
  63. /package/.next-prod/static/{7pu1LXbRRLfg05VN3u39s → bOkuiIr_nWzG5GjPLNqdN}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- [{"name":"run-webpack","duration":19799218,"timestamp":143062609,"id":14,"parentId":1,"tags":{},"startTime":1779817892339,"traceId":"98826c66cc2d55a4"},{"name":"run-typescript","duration":16474894,"timestamp":162871841,"id":1519,"parentId":1,"tags":{},"startTime":1779817912148,"traceId":"98826c66cc2d55a4"},{"name":"static-check","duration":1046300,"timestamp":179379791,"id":1522,"parentId":1,"tags":{},"startTime":1779817928656,"traceId":"98826c66cc2d55a4"},{"name":"static-generation","duration":5774227,"timestamp":180539499,"id":1778,"parentId":1,"tags":{},"startTime":1779817929815,"traceId":"98826c66cc2d55a4"},{"name":"collect-build-traces","duration":18014017,"timestamp":180426813,"id":1775,"parentId":1,"tags":{},"startTime":1779817929703,"traceId":"98826c66cc2d55a4"},{"name":"telemetry-flush","duration":57,"timestamp":198445089,"id":1787,"parentId":1,"tags":{},"startTime":1779817947721,"traceId":"98826c66cc2d55a4"},{"name":"next-build","duration":55513834,"timestamp":142931325,"id":1,"tags":{"buildMode":"default","version":"16.2.6","bundler":"webpack","has-custom-webpack-config":"true","use-build-worker":"false"},"startTime":1779817892207,"traceId":"98826c66cc2d55a4"}]
1
+ [{"name":"run-webpack","duration":20896395,"timestamp":174952275,"id":14,"parentId":1,"tags":{},"startTime":1780281928939,"traceId":"3ec3dff617736784"},{"name":"run-typescript","duration":17461310,"timestamp":195858899,"id":1519,"parentId":1,"tags":{},"startTime":1780281949846,"traceId":"3ec3dff617736784"},{"name":"static-check","duration":1101493,"timestamp":213361199,"id":1522,"parentId":1,"tags":{},"startTime":1780281967348,"traceId":"3ec3dff617736784"},{"name":"static-generation","duration":6075258,"timestamp":214649341,"id":1778,"parentId":1,"tags":{},"startTime":1780281968637,"traceId":"3ec3dff617736784"},{"name":"collect-build-traces","duration":19739218,"timestamp":214463475,"id":1775,"parentId":1,"tags":{},"startTime":1780281968451,"traceId":"3ec3dff617736784"},{"name":"telemetry-flush","duration":64,"timestamp":234206747,"id":1787,"parentId":1,"tags":{},"startTime":1780281988194,"traceId":"3ec3dff617736784"},{"name":"next-build","duration":59413969,"timestamp":174792856,"id":1,"tags":{"buildMode":"default","version":"16.2.6","bundler":"webpack","has-custom-webpack-config":"true","use-build-worker":"false"},"startTime":1780281928780,"traceId":"3ec3dff617736784"}]
package/README.md CHANGED
@@ -26,7 +26,7 @@
26
26
 
27
27
  ---
28
28
 
29
- > **OpenCockpit is the open-source Claude Code GUI** — and a single canvas for whatever agent you bring next. Run multi-project Claude sessions out of the box; pop open a tab for **OpenAI Codex, DeepSeek, Kimi, or local Ollama** whenever you need. Built-in terminal, Chrome control, PostgreSQL / MySQL / Redis bubbles, code review, and slash modes — all local.
29
+ > **OpenCockpit is the open-source Claude Code GUI** — and a single canvas for whatever agent you bring next. Run multi-project Claude sessions out of the box; pop open a tab for **Codex, DeepSeek, Kimi, or local Ollama** whenever you need. Built-in terminal, Chrome control, PostgreSQL / MySQL / Redis bubbles, code review, and slash modes — all local.
30
30
 
31
31
  https://github.com/user-attachments/assets/18f1a5dc-64f3-4ff6-b9fc-9cd08181fbb8
32
32
 
@@ -42,7 +42,7 @@ Cockpit is the instrument panel. It does **not** replace Claude Code; it stands
42
42
 
43
43
  | Pain with raw Claude Code | What Cockpit adds |
44
44
  |---|---|
45
- | Stuck on one model | **5 engines side by side** in tabs: Claude (default), OpenAI Codex, DeepSeek, Kimi, local Ollama — each its own session |
45
+ | Stuck on one model | **5 engines side by side** in tabs: Claude (default), Codex, DeepSeek, Kimi, local Ollama — each its own session |
46
46
  | One session at a time, terminal chaos at 3+ projects | **Multi-project tabs**, parallel agent sessions, red-dot inbox, desktop notifications |
47
47
  | Image attachments are awkward | Drop / paste images straight into chat |
48
48
  | "What was I debugging yesterday?" | Cmd+K cross-project session browser, pinning, forking |
@@ -58,7 +58,7 @@ Cockpit is the instrument panel. It does **not** replace Claude Code; it stands
58
58
  ### Engines — Claude by default, bring any agent you want
59
59
 
60
60
  - **Claude** *(default)* — full official Agent SDK; zero setup if `claude` CLI is already configured
61
- - **OpenAI Codex** — reuses your `~/.codex` config; same chat, same shell + bubbles
61
+ - **Codex** — reuses your `~/.codex` config; same chat, same shell + bubbles
62
62
  - **DeepSeek** — Anthropic-compatible endpoint via the Claude SDK; paste a key, pick `v4-pro` or `v4-flash`
63
63
  - **Kimi** *(Moonshot)* — tool calls render in chat just like Claude's
64
64
  - **Ollama** — auto-starts the daemon; pick any pulled model from the chat header; fully offline
@@ -146,7 +146,7 @@ No install, no AI chat (read-only sandbox, 5 min):
146
146
 
147
147
  ### Optional, per non-Claude engine
148
148
 
149
- - **OpenAI Codex** — log in once with `codex login` to populate `~/.codex`
149
+ - **Codex** — log in once with `codex login` to populate `~/.codex`
150
150
  - **DeepSeek** — get an API key at [api-docs.deepseek.com](https://api-docs.deepseek.com/); paste it into the engine picker
151
151
  - **Kimi (Moonshot)** — get an API key at [platform.moonshot.cn](https://platform.moonshot.cn/); paste it into the engine picker
152
152
  - **Ollama** — install [ollama.com](https://ollama.com/) and `ollama pull <model>`; Cockpit auto-starts the daemon
@@ -207,7 +207,7 @@ Next.js 16 · React 19 · TypeScript · TailwindCSS · xterm.js · node-pty · S
207
207
 
208
208
  ## Contributing
209
209
 
210
- Issues and PRs welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) and [GUIDE.md](GUIDE.md).
210
+ Issues and PRs welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) and the [OpenCockpit docs](https://opencockpit.dev/en/docs/).
211
211
 
212
212
  ## License
213
213
 
package/README.zh.md CHANGED
@@ -26,7 +26,7 @@
26
26
 
27
27
  ---
28
28
 
29
- > **OpenCockpit 是开源的 Claude Code GUI** —— 也是你想接入的任何 Agent 的统一画布。多项目 Claude 会话开箱即用;想用 **OpenAI Codex、DeepSeek、Kimi 或本地 Ollama**?直接新开一个 tab。内置终端、Chrome 自动化、PostgreSQL / MySQL / Redis 气泡、代码评审与斜杠模式 —— 全部本地。
29
+ > **OpenCockpit 是开源的 Claude Code GUI** —— 也是你想接入的任何 Agent 的统一画布。多项目 Claude 会话开箱即用;想用 **Codex、DeepSeek、Kimi 或本地 Ollama**?直接新开一个 tab。内置终端、Chrome 自动化、PostgreSQL / MySQL / Redis 气泡、代码评审与斜杠模式 —— 全部本地。
30
30
 
31
31
  https://github.com/user-attachments/assets/18f1a5dc-64f3-4ff6-b9fc-9cd08181fbb8
32
32
 
@@ -42,7 +42,7 @@ Cockpit 就是那个仪表盘。它**不替代** Claude Code,而是站在官
42
42
 
43
43
  | 裸用 Claude Code 的痛 | Cockpit 的解法 |
44
44
  |---|---|
45
- | 只能用一个模型 | **5 个引擎按 tab 并排**:Claude(默认)、OpenAI Codex、DeepSeek、Kimi、本地 Ollama —— 每个 tab 独立会话 |
45
+ | 只能用一个模型 | **5 个引擎按 tab 并排**:Claude(默认)、Codex、DeepSeek、Kimi、本地 Ollama —— 每个 tab 独立会话 |
46
46
  | 一次只能开一个会话,3+ 项目就乱 | **多项目标签页**、并发 Agent 会话、红点收件箱、桌面通知 |
47
47
  | 图片附件麻烦 | 拖拽 / 粘贴图片直接进对话 |
48
48
  | "我昨天调的那个 bug 在哪?" | Cmd+K 跨项目会话浏览,会话固定 / 分叉 |
@@ -58,7 +58,7 @@ Cockpit 就是那个仪表盘。它**不替代** Claude Code,而是站在官
58
58
  ### 引擎 —— 默认 Claude,也接得住你想要的任何 Agent
59
59
 
60
60
  - **Claude** *(默认)* —— 完整官方 Agent SDK;`claude` CLI 已配置即零额外设置
61
- - **OpenAI Codex** —— 直接读 `~/.codex` 配置,聊天 / Shell / 气泡都一样
61
+ - **Codex** —— 直接读 `~/.codex` 配置,聊天 / Shell / 气泡都一样
62
62
  - **DeepSeek** —— 通过 Claude SDK 走 Anthropic 兼容端点;粘 Key,选 `v4-pro` 或 `v4-flash`
63
63
  - **Kimi** *(Moonshot)* —— 函数调用在聊天里完整渲染,跟 Claude 一样
64
64
  - **Ollama** —— 自动拉起守护进程;从聊天头部下拉任意已 pull 的模型;完全离线
@@ -146,7 +146,7 @@ Cockpit 就是那个仪表盘。它**不替代** Claude Code,而是站在官
146
146
 
147
147
  ### 可选,按引擎
148
148
 
149
- - **OpenAI Codex** —— 执行一次 `codex login` 即可生成 `~/.codex` 配置
149
+ - **Codex** —— 执行一次 `codex login` 即可生成 `~/.codex` 配置
150
150
  - **DeepSeek** —— 到 [api-docs.deepseek.com](https://api-docs.deepseek.com/) 申请 API Key,在引擎选择器里粘贴
151
151
  - **Kimi (Moonshot)** —— 到 [platform.moonshot.cn](https://platform.moonshot.cn/) 申请 API Key,在引擎选择器里粘贴
152
152
  - **Ollama** —— 安装 [ollama.com](https://ollama.com/) 并 `ollama pull <model>`;Cockpit 会自动拉起守护进程
@@ -207,7 +207,7 @@ Next.js 16 · React 19 · TypeScript · TailwindCSS · xterm.js · node-pty · S
207
207
 
208
208
  ## 贡献
209
209
 
210
- 欢迎 Issue 和 PR。详见 [CONTRIBUTING.md](CONTRIBUTING.md) [GUIDE.md](GUIDE.md)。
210
+ 欢迎 Issue 和 PR。详见 [CONTRIBUTING.md](CONTRIBUTING.md) [OpenCockpit 文档](https://opencockpit.dev/zh/docs/)。
211
211
 
212
212
  ## 许可证
213
213
 
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Centralized messages & generic example pool for the browser CLI.
3
+ *
4
+ * ALL user-facing text (help / errors / warnings) MUST source examples from
5
+ * EXAMPLES below. Never inline business-specific selectors or API paths.
6
+ *
7
+ * Single source of truth — PR review greps for case-specific leakage:
8
+ * grep -E '<known case keywords>' bin/cock-browser.* chrome-extension/messages.js
9
+ *
10
+ * The extension side has its own copy (chrome-extension/messages.js); the
11
+ * subset that the extension generates locally (e.g. STALE_REF_MSG) lives
12
+ * there. Templates here are CLI-side only.
13
+ */
14
+
15
+ // ─────────────────────────────────────────────────────────
16
+ // Generic example pool. DO NOT add case-specific values.
17
+ // ─────────────────────────────────────────────────────────
18
+
19
+ export const EXAMPLES = Object.freeze({
20
+ selectorEmail: 'input[name="email"]',
21
+ selectorPassword: 'input[type="password"]',
22
+ selectorSubmit: 'button[type="submit"]',
23
+ selectorAriaSave: 'button[aria-label="Save"]',
24
+ selectorSearchBox: 'input[role="searchbox"]',
25
+ selectorStatus: '[role="status"]',
26
+ selectorContentEditable: '[contenteditable="true"]',
27
+ selectorLoginForm: 'form#login',
28
+ textSignIn: 'Sign in',
29
+ textSave: 'Save',
30
+ textSubmit: 'Submit',
31
+ apiUsersMe: '/api/users/me',
32
+ apiItems: '/api/items',
33
+ apiItemsId: '/api/items/123',
34
+ });
35
+
36
+ // ─────────────────────────────────────────────────────────
37
+ // CLI-side error / warn templates
38
+ // (server-side errors come back as data.error and are printed verbatim;
39
+ // the templates below cover errors the CLI itself originates.)
40
+ // ─────────────────────────────────────────────────────────
41
+
42
+ export const TIMEOUT_MSG = (timeoutMs, id) =>
43
+ `Timeout: no response within ${timeoutMs}ms.
44
+ Likely cause: the page is busy (long render / streaming / network).
45
+ Diagnose:
46
+ cockpit browser ${id} health # is extension alive? (server-side, never blocks)
47
+ cockpit browser ${id} wait --extension-ready # wait until responsive
48
+ cockpit browser ${id} wait --network-idle # wait for the page to settle
49
+ If health returns alive but evaluate still hangs, the page itself is blocked.
50
+ Consider a service-level test if the page is driven by an async LLM/agent flow.`;
51
+
52
+ export const CONNECT_REFUSED_MSG = (baseUrl) =>
53
+ `Connection refused: Cockpit server not reachable at ${baseUrl}.
54
+ Recover:
55
+ 1. Start the server: \`cockpit\` (prod, default port 3457) or \`cockpit-dev\` (dev, default 3456)
56
+ 2. Or set COCKPIT_PORT env var if your server runs on a non-default port.`;
57
+
58
+ // Used by F1.7 post-verify when click / key / submit succeeded per CDP
59
+ // but no observable side-effect happened in the verify window.
60
+ export const CLICK_NO_OP_WARN = (action, id, observed) =>
61
+ `⚠ ${action} succeeded per CDP but no DOM mutation / URL change / network request in ${observed.windowMs}ms.
62
+ Likely a no-op (no real handler / portal-rendered / framework not listening).
63
+ Observed: url-changed=${observed.urlChanged} dom-changed=${observed.domChanged} new-requests=${observed.newRequests}
64
+ Try one of:
65
+ cockpit browser ${id} evaluate "(() => { const el = document.querySelector('${EXAMPLES.selectorAriaSave}'); el.click(); return el.outerHTML.slice(0,200); })()"
66
+ cockpit browser ${id} submit --form-selector '${EXAMPLES.selectorLoginForm}'
67
+ cockpit browser ${id} fetch ${EXAMPLES.apiItems} --method POST --body '{}'`;
68
+
69
+ // ─────────────────────────────────────────────────────────
70
+ // help fragments (composed in cock-browser.mjs printHelp)
71
+ // ─────────────────────────────────────────────────────────
72
+
73
+ export const HELP_WHEN_NOT_TO_USE =
74
+ `── When NOT to use this CLI ───────────────────────────
75
+ - Testing LLM-agent driven flows end-to-end: the agent's stochastic tool
76
+ choice and stop_reason make UI assertions flaky. Prefer a thin runtime
77
+ script that calls the same middleware / service directly with controlled
78
+ inputs.
79
+
80
+ - Pages that stream / re-render for >10s: evaluate calls queue behind page
81
+ work and time out (~15s default). Run \`wait --extension-ready\` between
82
+ acts and asserts; if it stays hung, pivot to a service-level test.
83
+
84
+ - Multi-tab / popup OAuth flows: each browser bubble tracks one tab. Open
85
+ the secondary tab in its own bubble or stub the OAuth handshake.`;
86
+
87
+ export const HELP_INTERACTION_BY_SELECTOR = (idForExamples) =>
88
+ `Interaction by selector (preferred — refs go stale on re-render):
89
+ click <ref|text> Click by ref (e5#v3), or fall back to:
90
+ click --text <substr> Click button/link by visible text or aria-label
91
+ e.g. click --text "${EXAMPLES.textSignIn}"
92
+ click --selector <css> Click first element matching CSS
93
+ e.g. click --selector '${EXAMPLES.selectorSubmit}'
94
+ fill <ref> <value> Fill via ref, or:
95
+ fill --selector <css> --value V Fill via native setter (works on React-controlled inputs)
96
+ e.g. fill --selector '${EXAMPLES.selectorEmail}' --value "user@example.com"
97
+ submit [--form-selector <css>] form.requestSubmit() — works where key Enter is ignored
98
+ e.g. submit --form-selector '${EXAMPLES.selectorLoginForm}'
99
+
100
+ Post-verify (click / key / submit / click-by-text/-selector):
101
+ --verify-ms <N> Window in ms to wait before re-probing page state
102
+ (default 1000). Lower = faster but more false positives
103
+ on slow-rendering React. Higher = more tolerant.
104
+ --skip-verify (or --no-verify) Disable post-verify for this command
105
+ (e.g. legit clicks that have no observable side-effect).`;
106
+
107
+ export const HELP_FETCH =
108
+ `Backend probing (inherits page auth):
109
+ fetch <url> GET, returns JSON or text
110
+ e.g. fetch ${EXAMPLES.apiUsersMe}
111
+ fetch <url> --method POST --body '{"name":"hello"}'
112
+ fetch <url> --json $.data.id Extract via simple JSONPath ($, .key, [N], [*])`;
113
+
114
+ export const HELP_HEALTH =
115
+ `Diagnostics:
116
+ health Server-side bridge state (never blocks page).
117
+ Returns: ws status, last command timestamp, pending count.
118
+ Use when evaluate times out to distinguish
119
+ "extension dead" vs "page busy".
120
+ health --deep Also probe the page itself (may block if page is busy).`;
121
+
122
+ export const HELP_WAIT =
123
+ `Wait (synchronisation between act and assert):
124
+ wait --text <substr> Wait for substring in body text
125
+ wait --selector <css> [--state visible|hidden|attached|detached]
126
+ Wait for element to reach state (default: visible)
127
+ e.g. wait --selector '${EXAMPLES.selectorStatus}' --state visible
128
+ wait --url <pat> Wait for URL match (substring or *-glob)
129
+ wait --network-idle [--quiet-ms 500] [--max-request-age-ms 30000]
130
+ Wait until 0 in-flight HTTP requests for quiet-ms.
131
+ Long-running (>max-request-age-ms) are ignored
132
+ so SSE / long-poll don't block.
133
+ e.g. wait --network-idle --quiet-ms 800
134
+ wait --dom-stable [--quiet-ms 300]
135
+ Wait until MutationObserver sees no changes
136
+ for quiet-ms (useful between act and snapshot).
137
+ wait --extension-ready [--quiet-ms 500]
138
+ CLI-side poll of \`health\` (never blocks on page).
139
+ Replaces manual \`until evaluate "1+1"\` loops.
140
+ wait --time <ms> Sleep <ms> (escape hatch — prefer above)
141
+ wait --ref <ref> Wait for ref to still be connected`;
142
+
143
+ export const HELP_LIFECYCLE =
144
+ `Lifecycle / fixtures:
145
+ status One-line summary: url, title, last console error,
146
+ last failed request, top visible buttons.
147
+ Run after a long gap before another act.
148
+ reset [--cookies] [--storage] [--cache] [--reload]
149
+ Atomic test-isolation. Combine flags as needed.
150
+ e.g. reset --cookies --storage --reload
151
+ set --type cookie --name K --value V [--domain D] [--path P] [--secure]
152
+ [--same-site Lax|Strict|None] [--expires <date>]
153
+ set --type local-storage --name K --value V
154
+ set --type session-storage --name K --value V
155
+ e.g. set --type cookie --name auth --value abc123 --secure
156
+ e.g. set --type local-storage --name theme --value '"dark"'`;
157
+
158
+ export const HELP_ASSERT =
159
+ `Assert (act + assert atoms; non-zero exit on failure):
160
+ assert --selector <css> [--text X | --visible <bool> | --attr "k=v"]
161
+ e.g. assert --selector '${EXAMPLES.selectorStatus}' --text "Saved"
162
+ e.g. assert --selector '${EXAMPLES.selectorSubmit}' --visible true
163
+ e.g. assert --selector '[role="dialog"]' --attr "aria-modal=true"
164
+ assert --ref <ref> --text/... Legacy ref-based form (refs go stale; prefer --selector)
165
+ assert --url <pat> URL substring or *-glob match
166
+ assert --title <substr>
167
+ assert --console-no-errors
168
+ assert --network --method M --url U --status S [--since <ms>]
169
+ Assert a matching request occurred in networkBuffer.
170
+ Status accepts ints or "2xx"/"4xx"/etc.
171
+ e.g. assert --network --method POST --url ${EXAMPLES.apiItems} --status 200
172
+ assert --fetch <url> [--fetch-method M] [--body B] [--fetch-status N]
173
+ [--jsonpath P --equals V | --contains V | --not-contains V]
174
+ Make a fetch and assert response. Inherits auth.
175
+ e.g. assert --fetch ${EXAMPLES.apiItems} --jsonpath '$.count' --equals 5
176
+ e.g. assert --fetch ${EXAMPLES.apiItems} --jsonpath '$[*].id' --contains 42`;