@phnx-labs/agents-cli 1.15.0 → 1.17.0
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/CHANGELOG.md +143 -39
- package/README.md +6 -6
- package/dist/commands/alias.js +2 -2
- package/dist/commands/browser-picker.d.ts +21 -0
- package/dist/commands/browser-picker.js +114 -0
- package/dist/commands/browser.js +793 -83
- package/dist/commands/cloud.js +8 -0
- package/dist/commands/commands.js +72 -22
- package/dist/commands/daemon.js +2 -2
- package/dist/commands/exec.js +70 -1
- package/dist/commands/hooks.js +71 -26
- package/dist/commands/mcp.js +81 -39
- package/dist/commands/plugins.js +224 -17
- package/dist/commands/prune.js +29 -1
- package/dist/commands/pull.js +3 -3
- package/dist/commands/repo.js +1 -1
- package/dist/commands/routines.js +2 -2
- package/dist/commands/secrets.js +154 -20
- package/dist/commands/sessions.js +62 -19
- package/dist/commands/{init.d.ts → setup.d.ts} +7 -6
- package/dist/commands/{init.js → setup.js} +22 -21
- package/dist/commands/skills.js +60 -19
- package/dist/commands/subagents.js +41 -13
- package/dist/commands/utils.d.ts +16 -0
- package/dist/commands/utils.js +32 -0
- package/dist/commands/view.js +78 -20
- package/dist/commands/workflows.d.ts +10 -0
- package/dist/commands/workflows.js +457 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +48 -36
- package/dist/lib/agents.js +2 -2
- package/dist/lib/auto-pull-worker.js +2 -3
- package/dist/lib/auto-pull.js +2 -2
- package/dist/lib/browser/cdp.d.ts +7 -1
- package/dist/lib/browser/cdp.js +32 -1
- package/dist/lib/browser/chrome.d.ts +10 -0
- package/dist/lib/browser/chrome.js +41 -3
- package/dist/lib/browser/devices.d.ts +4 -0
- package/dist/lib/browser/devices.js +27 -0
- package/dist/lib/browser/drivers/local.js +22 -6
- package/dist/lib/browser/drivers/ssh.js +9 -2
- package/dist/lib/browser/input.d.ts +1 -0
- package/dist/lib/browser/input.js +3 -0
- package/dist/lib/browser/ipc.js +158 -23
- package/dist/lib/browser/profiles.d.ts +10 -2
- package/dist/lib/browser/profiles.js +122 -37
- package/dist/lib/browser/service.d.ts +91 -13
- package/dist/lib/browser/service.js +767 -132
- package/dist/lib/browser/types.d.ts +91 -3
- package/dist/lib/browser/types.js +16 -0
- package/dist/lib/cloud/rush.d.ts +28 -1
- package/dist/lib/cloud/rush.js +69 -14
- package/dist/lib/cloud/store.js +2 -2
- package/dist/lib/commands.d.ts +1 -15
- package/dist/lib/commands.js +11 -7
- package/dist/lib/daemon.js +2 -3
- package/dist/lib/doctor-diff.js +4 -4
- package/dist/lib/events.js +2 -2
- package/dist/lib/hooks.d.ts +11 -7
- package/dist/lib/hooks.js +138 -49
- package/dist/lib/migrate.d.ts +1 -1
- package/dist/lib/migrate.js +1237 -22
- package/dist/lib/models.js +2 -2
- package/dist/lib/permissions.d.ts +8 -66
- package/dist/lib/permissions.js +18 -18
- package/dist/lib/plugins.d.ts +94 -24
- package/dist/lib/plugins.js +702 -123
- package/dist/lib/pty-server.js +9 -10
- package/dist/lib/resource-patterns.d.ts +41 -0
- package/dist/lib/resource-patterns.js +82 -0
- package/dist/lib/resources/hooks.d.ts +5 -1
- package/dist/lib/resources/hooks.js +21 -4
- package/dist/lib/resources/index.d.ts +17 -0
- package/dist/lib/resources/index.js +7 -0
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/resources/workflows.d.ts +24 -0
- package/dist/lib/resources/workflows.js +110 -0
- package/dist/lib/resources.d.ts +6 -1
- package/dist/lib/resources.js +12 -2
- package/dist/lib/rotate.js +3 -4
- package/dist/lib/session/active.d.ts +3 -0
- package/dist/lib/session/active.js +92 -6
- package/dist/lib/session/cloud.js +2 -2
- package/dist/lib/session/db.d.ts +18 -0
- package/dist/lib/session/db.js +109 -5
- package/dist/lib/session/discover.d.ts +6 -0
- package/dist/lib/session/discover.js +55 -29
- package/dist/lib/session/team-filter.js +2 -2
- package/dist/lib/shims.d.ts +4 -52
- package/dist/lib/shims.js +23 -15
- package/dist/lib/skills.js +6 -2
- package/dist/lib/sqlite.js +10 -4
- package/dist/lib/state.d.ts +101 -16
- package/dist/lib/state.js +179 -31
- package/dist/lib/subagents.d.ts +28 -0
- package/dist/lib/subagents.js +98 -1
- package/dist/lib/sync-manifest.d.ts +1 -1
- package/dist/lib/sync-manifest.js +3 -3
- package/dist/lib/teams/persistence.js +15 -5
- package/dist/lib/teams/registry.js +2 -2
- package/dist/lib/types.d.ts +75 -17
- package/dist/lib/types.js +3 -3
- package/dist/lib/usage.js +2 -2
- package/dist/lib/versions.d.ts +3 -0
- package/dist/lib/versions.js +158 -47
- package/dist/lib/workflows.d.ts +79 -0
- package/dist/lib/workflows.js +233 -0
- package/package.json +1 -5
- package/scripts/postinstall.js +60 -59
- package/dist/commands/fork.d.ts +0 -10
- package/dist/commands/fork.js +0 -146
package/CHANGELOG.md
CHANGED
|
@@ -1,62 +1,166 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 1.
|
|
3
|
+
## 1.17.0
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**Workflows: a new first-class resource**
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
- Accounts will stay healthy across runs without requiring re-login
|
|
7
|
+
- `agents workflows list / add / remove / view` — WORKFLOW.md bundles (with optional `subagents/`, `skills/`, `plugins/`) install from GitHub or a local path and resolve through the same system → user → project layer model as every other resource.
|
|
8
|
+
- `agents run <name>` resolves a workflow or named subagent as an orchestrator: prepends WORKFLOW.md / AGENT.md body to the prompt, copies `subagents/*` into `~/.claude/agents/` for Agent-tool discovery, and syncs workflow-scoped `skills/` and `plugins/` at run time.
|
|
9
|
+
- `agents view` now has a workflows section.
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
**Browser**
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
- Port-per-profile with auto-allocation and viewport enforcement — concurrent browser profiles no longer collide on CDP ports.
|
|
14
|
+
- `agents browser scroll` plus new `profiles launch`, `profiles doctor`, `profiles prime`, viewport position, and port diagnostics commands.
|
|
15
|
+
- `agents browser profiles list` now shows a description column when any profile has one.
|
|
16
|
+
- `isProcessRunning` treats EPERM as process-alive (fixes false-negative on sandboxed processes).
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
|
|
18
|
+
**Cloud dispatch**
|
|
19
|
+
|
|
20
|
+
- `--balanced` strategy and `--upload-account-tokens` flag on cloud dispatch.
|
|
21
|
+
- Remote account API client; `--balanced` skips the client manifest path.
|
|
22
|
+
|
|
23
|
+
**Plugin system extension**
|
|
24
|
+
|
|
25
|
+
- Plugins now ship with `commands/`, `agents/`, `bin/`, MCP configs, settings, and `install` / `update` hooks. Discovery and sync extended end-to-end.
|
|
26
|
+
|
|
27
|
+
**Secrets**
|
|
28
|
+
|
|
29
|
+
- `agents secrets import <bundle> --from-1password` / `export <bundle> --to-1password` with vault picker, skip-empty-fields on import, overwrite-only-with-`--force` on export. Wires the existing 1Password library into the CLI.
|
|
30
|
+
|
|
31
|
+
**Sandbox**
|
|
32
|
+
|
|
33
|
+
- `scripts/sandbox.sh --pr` — author real PRs from a Crabbox-isolated box via a bare-mirror clone off main.
|
|
34
|
+
- `sandbox.sh --linear` and `--post-file` post run output to Linear tickets.
|
|
35
|
+
- Dynamic GitHub App token, `gh` CLI installed, stale git credentials cleaned.
|
|
36
|
+
|
|
37
|
+
**Sessions / SQLite concurrency**
|
|
38
|
+
|
|
39
|
+
- Scan coordinator prevents concurrent session indexing.
|
|
40
|
+
- SQLite concurrency hardened with `BEGIN IMMEDIATE` and ledger recheck on contention.
|
|
41
|
+
- Session discovery uses `getHistoryDir` for version roots and backup paths.
|
|
42
|
+
|
|
43
|
+
**Run / shims / hooks**
|
|
44
|
+
|
|
45
|
+
- Versioned alias shims regenerate on startup if missing.
|
|
46
|
+
- Hooks prefer version-home scripts to prevent path breakage when the source dir moves.
|
|
47
|
+
- Linux: claude shim sources `CLAUDE_CODE_OAUTH_TOKEN` from the per-version `.oauth_token` file when unset.
|
|
48
|
+
|
|
49
|
+
**Resource UI**
|
|
50
|
+
|
|
51
|
+
- `agents view` replaces path columns with OSC 8 hyperlinks for commands, skills, and rules.
|
|
52
|
+
- Flat version resource lists replaced with source-pattern selection.
|
|
53
|
+
|
|
54
|
+
**CI / security**
|
|
55
|
+
|
|
56
|
+
- Gitleaks secret-scanning workflow on every push (switched to the free CLI, no org license needed).
|
|
57
|
+
|
|
58
|
+
**Postinstall**
|
|
59
|
+
|
|
60
|
+
- Correct shims dir, expanded aliases, prints changelog on install.
|
|
61
|
+
|
|
62
|
+
**Dev**
|
|
63
|
+
|
|
64
|
+
- Test isolation via vitest `pool: 'forks'`; mock state paths instead of hitting real `~/.agents/`.
|
|
65
|
+
- Concurrent-writes benchmark for the session indexer.
|
|
66
|
+
- Dead code + phantom deps removed: `src/commands/fork.ts`, `@aws-sdk/client-s3`, `@modelcontextprotocol/sdk`, `semver`.
|
|
67
|
+
|
|
68
|
+
## 1.16.0
|
|
21
69
|
|
|
22
|
-
|
|
70
|
+
**System-repo sweep: ~/.agents-system reduced to npm-shipped defaults only**
|
|
23
71
|
|
|
24
|
-
|
|
72
|
+
- New migrators move every form of operational state out of ~/.agents-system into user-side buckets: sessions, teams (live + per-run), trash, repos (→ ~/.agents-<alias>/ peer dirs), legacy swarm/, cache/, cloud/.
|
|
73
|
+
- SQLite DBs merge row-level (INSERT OR IGNORE) into the user-side DB; filesystem dirs merge dir-by-dir with user-side winning on collision.
|
|
74
|
+
- Dead artifacts dropped automatically: bin/agents-keychain-*, empty shims/, .DS_Store-only versions/ skeletons.
|
|
75
|
+
- Unrecognized leftover dirs print a one-line stderr warning so future drift surfaces immediately.
|
|
76
|
+
- Migration diagnostics moved to stderr — `eval "$(agents secrets export …)"` stops being polluted by log lines.
|
|
77
|
+
- DB merge now skips FTS5 virtual + shadow tables (previously corrupted the session_text index). Indexer re-populates FTS on the next scan.
|
|
78
|
+
- Stale ~/.agents-system/agents.yaml is now dropped when a user copy exists.
|
|
25
79
|
|
|
26
|
-
|
|
27
|
-
- `agents init` and `agents pull` now bootstrap and sync the fixed system repo in `~/.agents-system/`.
|
|
28
|
-
- `agents repo init` now supports `--from <source>` and no longer pushes users toward generated names like `~/.agents-mine`; `~/.agents` is now the recommended clean path for a personal repo.
|
|
80
|
+
**~/.agents split into .history/ and .cache/ buckets**
|
|
29
81
|
|
|
30
|
-
|
|
82
|
+
- Durable runtime state (sessions, versions, runs, teams/agents, trash, backups) moves to ~/.agents/.history/.
|
|
83
|
+
- Regenerable runtime state (shims, packages, cloud, logs, swarmify, helpers, browser runtime, fetch cache, dot-files) moves to ~/.agents/.cache/.
|
|
84
|
+
- Single-line gitignore for backing up ~/.agents/ — no more per-subdir cherry-picking.
|
|
31
85
|
|
|
32
|
-
|
|
33
|
-
- New subcommands mirror the old daemon controls under `routines`: `agents routines start`, `stop`, `status`, `scheduler-logs`. The word "daemon" is no longer exposed in user-facing help.
|
|
34
|
-
- `agents daemon <start|stop|status|logs>` is **deprecated**. It still works but prints a migration warning and is hidden from top-level help. Will be removed in v2.0.
|
|
35
|
-
- Top-level help restructured: the old "Automation" grab-bag is gone. Commands are now grouped as **Run agents** (`run`, `teams`, `sessions`), **Schedule** (`routines`), and **Helpers** (`pty`).
|
|
86
|
+
**Browser: profiles fold into agents.yaml + many new automation commands**
|
|
36
87
|
|
|
37
|
-
|
|
88
|
+
- Profile YAMLs at ~/.agents/browser/profiles/*.yaml now live as a `browser:` section in agents.yaml. Single user-facing file, single sync.
|
|
89
|
+
- Single window per profile; `start` renamed to `open`; new tab subcommands; session history with profile picker; viewport piped through to the launched browser.
|
|
90
|
+
- New commands: `agents browser set viewport`, `set device`, `devices`, `console`, `errors`, `requests`, `responsebody`, `wait`, `download`, `waitdownload`.
|
|
38
91
|
|
|
39
|
-
|
|
92
|
+
**Hooks: hooks.yaml folded into agents.yaml `hooks:` section**
|
|
40
93
|
|
|
41
|
-
|
|
94
|
+
- ~/.agents/hooks.yaml is migrated into agents.yaml on first run; the standalone file is removed.
|
|
95
|
+
- System repo ships the same shape — one config file, layered project > user > system.
|
|
42
96
|
|
|
43
|
-
|
|
44
|
-
- Existing users whose upstream still points at the old default see a one-time nudge on `agents pull --upstream` with the command to switch. Nothing else breaks; legacy remotes continue to work.
|
|
97
|
+
**Sessions & secrets**
|
|
45
98
|
|
|
46
|
-
|
|
99
|
+
- `agents secrets exec <bundle> -- <command>` injects a bundle's env vars into a one-shot subprocess (no shell-state leakage).
|
|
100
|
+
- `agents sessions` now groups active sessions by workspace and surfaces session topics in the picker.
|
|
101
|
+
- Session discovery scans both version repos; migrator merges overlapping versions instead of leaving duplicates.
|
|
47
102
|
|
|
48
|
-
|
|
49
|
-
- Positional query resolves to a session ID (renders directly), a path (`.`, `../`, `/path`) to filter by project, or free text for search
|
|
50
|
-
- Claude `/resume` history fallback (previously only in `view`) now fires from the top-level command too
|
|
51
|
-
- Picker shows the selected-session preview by default; space hides it
|
|
103
|
+
**Renames**
|
|
52
104
|
|
|
53
|
-
|
|
105
|
+
- `agents init` → `agents setup`.
|
|
106
|
+
- `permissions/sets/` → `permissions/presets/` (resource directory + on-disk migration to match rules/presets convention).
|
|
54
107
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
|
|
59
|
-
|
|
108
|
+
**Dev**
|
|
109
|
+
|
|
110
|
+
- Crabbox remote-test profile (~$0.14/hr) + `scripts/sandbox.sh` documented in README and CLAUDE.md. Tests run remotely to avoid freezing the local machine.
|
|
111
|
+
|
|
112
|
+
## 1.15.0
|
|
113
|
+
|
|
114
|
+
**Secrets: Linux support via libsecret/GNOME Keyring**
|
|
115
|
+
|
|
116
|
+
- `agents secrets` now works on Linux backed by libsecret/GNOME Keyring with the same UX as macOS Keychain. Headless workarounds documented.
|
|
117
|
+
- New `agents password generate` subcommand.
|
|
118
|
+
- Lifecycle events emitted for secrets and other subsystems; richer metadata (timing helpers) on the events system.
|
|
119
|
+
|
|
120
|
+
**Browser**
|
|
121
|
+
|
|
122
|
+
- HTTP and WebSocket endpoint support for remote browsers.
|
|
123
|
+
- Concurrent Electron profile forks no longer step on each other; cleanup hardened.
|
|
124
|
+
- Remote browser restart works; SSH port handling improved; page target created when none exists for Electron apps.
|
|
125
|
+
- Events emitted for navigation and screenshots.
|
|
126
|
+
|
|
127
|
+
**First-run UX**
|
|
128
|
+
|
|
129
|
+
- Improved new-user experience: clearer CLI help, better defaults, audit-log opt-out, better run-timing display.
|
|
130
|
+
|
|
131
|
+
**Prune**
|
|
132
|
+
|
|
133
|
+
- `agents prune` learned `trash`, `sessions`, and `runs` cleanup targets.
|
|
134
|
+
|
|
135
|
+
**Fixes**
|
|
136
|
+
|
|
137
|
+
- Command-injection hole in daemon + secrets closed.
|
|
138
|
+
- Layered permission resolution corrected; daemon tests isolated from real user state.
|
|
139
|
+
- `.tmp-bun` gitignore pattern fixed.
|
|
140
|
+
- `codex` interactive mode no longer routes through `exec` subcommand.
|
|
141
|
+
|
|
142
|
+
**Docs**
|
|
143
|
+
|
|
144
|
+
- Security/privacy section in README, browser skill + automation guide, FAQ updated with audit-log transparency.
|
|
145
|
+
|
|
146
|
+
## 1.14.6
|
|
147
|
+
|
|
148
|
+
**Fix: OAuth token refresh now persists to Keychain**
|
|
149
|
+
|
|
150
|
+
- Fixed bug where refreshed Claude OAuth tokens were used but never saved back to macOS Keychain
|
|
151
|
+
- Previously, agents-cli would refresh expired tokens on each run but discard them, eventually exhausting the refresh token
|
|
152
|
+
- Now refreshed `accessToken`, `refreshToken`, and `expiresAt` are written back to Keychain after successful refresh
|
|
153
|
+
- Accounts will stay healthy across runs without requiring re-login
|
|
154
|
+
|
|
155
|
+
## 1.14.5
|
|
156
|
+
|
|
157
|
+
**Browser: custom binary and Electron app support**
|
|
158
|
+
|
|
159
|
+
- Added `binary` field to browser profiles for specifying custom executable paths (e.g., Electron apps like Rush)
|
|
160
|
+
- Added `electron` field to browser profiles — when true, uses existing windows instead of creating new ones (Electron doesn't support `Target.createTarget`)
|
|
161
|
+
- New `custom` browser type that requires a binary path
|
|
162
|
+
- Works with both local and SSH-based browser connections
|
|
163
|
+
- Example profile for Rush: `agents browser profiles edit rush --browser custom --binary "/Applications/Rush.app/Contents/MacOS/Rush" --electron`
|
|
60
164
|
|
|
61
165
|
## 1.12.0
|
|
62
166
|
|
package/README.md
CHANGED
|
@@ -253,12 +253,12 @@ Give agents access to a real browser — no relay extension, no cloud service, n
|
|
|
253
253
|
agents browser profiles create work --browser chrome
|
|
254
254
|
|
|
255
255
|
# Start a task, navigate, interact
|
|
256
|
-
agents browser start login-flow --
|
|
257
|
-
agents browser navigate login-flow https://app.example.com
|
|
256
|
+
agents browser start --profile work --task login-flow --url https://app.example.com
|
|
258
257
|
agents browser refs login-flow # Get interactive element refs
|
|
259
|
-
agents browser click login-flow
|
|
260
|
-
agents browser type login-flow
|
|
258
|
+
agents browser click login-flow 42 # Click element ref 42
|
|
259
|
+
agents browser type login-flow 15 "hello" # Type into element ref 15
|
|
261
260
|
agents browser screenshot login-flow # Smart resizing, token-efficient
|
|
261
|
+
agents browser done login-flow # Close task's tabs when finished
|
|
262
262
|
```
|
|
263
263
|
|
|
264
264
|
### Why this works where Playwright fails
|
|
@@ -294,9 +294,9 @@ agents browser profiles create bank --browser chrome --secrets bank-creds
|
|
|
294
294
|
Control Electron apps (Slack, Discord, VS Code, your own app) with custom binaries:
|
|
295
295
|
|
|
296
296
|
```bash
|
|
297
|
-
agents browser profiles create
|
|
297
|
+
agents browser profiles create slack \
|
|
298
298
|
--browser custom \
|
|
299
|
-
--binary "/Applications/
|
|
299
|
+
--binary "/Applications/Slack.app/Contents/MacOS/Slack" \
|
|
300
300
|
--electron
|
|
301
301
|
```
|
|
302
302
|
|
package/dist/commands/alias.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
|
-
import {
|
|
4
|
+
import { getUserAgentsDir } from '../lib/state.js';
|
|
5
5
|
import { getShimsDir } from '../lib/shims.js';
|
|
6
6
|
import { ALL_AGENT_IDS, AGENTS } from '../lib/agents.js';
|
|
7
|
-
const ALIASES_FILE = path.join(
|
|
7
|
+
const ALIASES_FILE = path.join(getUserAgentsDir(), 'aliases.json');
|
|
8
8
|
/** Names that would clobber an agent CLI shim or the `agents` binary itself. */
|
|
9
9
|
function reservedNames() {
|
|
10
10
|
const reserved = new Set(['agents']);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ProfileStatus, TaskStatus } from '../lib/browser/types.js';
|
|
2
|
+
export interface BrowserTask {
|
|
3
|
+
task: TaskStatus;
|
|
4
|
+
profile: ProfileStatus;
|
|
5
|
+
}
|
|
6
|
+
export interface PickedBrowserTask {
|
|
7
|
+
task: BrowserTask;
|
|
8
|
+
action: 'view' | 'stop';
|
|
9
|
+
}
|
|
10
|
+
/** Build the preview pane for a browser task. */
|
|
11
|
+
export declare function buildBrowserPreview(item: BrowserTask): string;
|
|
12
|
+
/** Build the list label for a browser task. */
|
|
13
|
+
export declare function buildBrowserLabel(item: BrowserTask, query: string): string;
|
|
14
|
+
export interface BrowserPickerConfig {
|
|
15
|
+
message: string;
|
|
16
|
+
tasks: BrowserTask[];
|
|
17
|
+
pageSize?: number;
|
|
18
|
+
initialSearch?: string;
|
|
19
|
+
}
|
|
20
|
+
/** Show an interactive browser task picker. */
|
|
21
|
+
export declare function browserTaskPicker(config: BrowserPickerConfig): Promise<PickedBrowserTask | null>;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive browser task picker with preview.
|
|
3
|
+
*
|
|
4
|
+
* Powers the fuzzy-searchable task list shown by `agents browser status` in a TTY.
|
|
5
|
+
* Shows task name, profile, domains, and tab count; preview pane shows full tab list.
|
|
6
|
+
*/
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { itemPicker } from '../lib/picker.js';
|
|
9
|
+
const DOT = chalk.gray(' · ');
|
|
10
|
+
function humanDuration(ms) {
|
|
11
|
+
const s = Math.floor(ms / 1000);
|
|
12
|
+
if (s < 60)
|
|
13
|
+
return `${s}s`;
|
|
14
|
+
const m = Math.floor(s / 60);
|
|
15
|
+
if (m < 60)
|
|
16
|
+
return `${m}m`;
|
|
17
|
+
const h = Math.floor(m / 60);
|
|
18
|
+
const mm = m % 60;
|
|
19
|
+
if (h < 24)
|
|
20
|
+
return mm ? `${h}h ${mm}m` : `${h}h`;
|
|
21
|
+
const d = Math.floor(h / 24);
|
|
22
|
+
const hh = h % 24;
|
|
23
|
+
return hh ? `${d}d ${hh}h` : `${d}d`;
|
|
24
|
+
}
|
|
25
|
+
function formatAge(ms) {
|
|
26
|
+
return humanDuration(Date.now() - ms) + ' ago';
|
|
27
|
+
}
|
|
28
|
+
function truncate(s, max) {
|
|
29
|
+
return s.length > max ? s.slice(0, max - 1) + '…' : s;
|
|
30
|
+
}
|
|
31
|
+
/** Build the preview pane for a browser task. */
|
|
32
|
+
export function buildBrowserPreview(item) {
|
|
33
|
+
const { task, profile } = item;
|
|
34
|
+
const lines = [];
|
|
35
|
+
// Line 1: Task name (ID: xxx)
|
|
36
|
+
lines.push(chalk.bold.white(`Task: ${task.name}`) + chalk.gray(` (${task.id})`));
|
|
37
|
+
// Line 2: Profile info
|
|
38
|
+
const profileParts = [chalk.cyan(profile.name)];
|
|
39
|
+
if (profile.port)
|
|
40
|
+
profileParts.push(`port ${profile.port}`);
|
|
41
|
+
if (profile.pid)
|
|
42
|
+
profileParts.push(`pid ${profile.pid}`);
|
|
43
|
+
lines.push(chalk.gray('Profile: ') + profileParts.join(DOT));
|
|
44
|
+
// Line 3: Timing
|
|
45
|
+
const started = formatAge(task.createdAt);
|
|
46
|
+
const duration = humanDuration(Date.now() - task.createdAt);
|
|
47
|
+
lines.push(chalk.gray('Started: ') + chalk.white(started) + DOT + chalk.gray('Duration: ') + chalk.white(duration));
|
|
48
|
+
// Blank line
|
|
49
|
+
lines.push('');
|
|
50
|
+
// Tabs section
|
|
51
|
+
if (task.tabs && task.tabs.length > 0) {
|
|
52
|
+
lines.push(chalk.gray('Tabs:'));
|
|
53
|
+
const termWidth = process.stdout.columns || 80;
|
|
54
|
+
const urlMax = Math.max(30, termWidth - 16);
|
|
55
|
+
for (const tab of task.tabs) {
|
|
56
|
+
const marker = tab.current ? chalk.yellow('*') : ' ';
|
|
57
|
+
const id = chalk.gray(tab.id);
|
|
58
|
+
const url = truncate(tab.url, urlMax);
|
|
59
|
+
lines.push(` ${id} ${marker} ${chalk.white(url)}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
lines.push(chalk.gray('No tabs open'));
|
|
64
|
+
}
|
|
65
|
+
return lines.join('\n');
|
|
66
|
+
}
|
|
67
|
+
/** Build the list label for a browser task. */
|
|
68
|
+
export function buildBrowserLabel(item, query) {
|
|
69
|
+
const { task, profile } = item;
|
|
70
|
+
const termWidth = process.stdout.columns || 80;
|
|
71
|
+
// Format: name profile tabs domains age
|
|
72
|
+
const name = task.name.padEnd(20);
|
|
73
|
+
const profileName = profile.name.padEnd(12);
|
|
74
|
+
const tabs = `${task.tabCount} tab${task.tabCount === 1 ? '' : 's'}`.padEnd(8);
|
|
75
|
+
const age = formatAge(task.createdAt);
|
|
76
|
+
// Domains - fill remaining space
|
|
77
|
+
const fixedWidth = 20 + 12 + 8 + 10; // name + profile + tabs + age
|
|
78
|
+
const domainsWidth = Math.max(10, termWidth - fixedWidth - 4);
|
|
79
|
+
const domains = task.domains?.length
|
|
80
|
+
? truncate(task.domains.join(', '), domainsWidth)
|
|
81
|
+
: chalk.gray('no sites');
|
|
82
|
+
// Highlight query matches
|
|
83
|
+
let label = `${name}${chalk.cyan(profileName)}${tabs}${domains.padEnd(domainsWidth)}${chalk.gray(age)}`;
|
|
84
|
+
if (query) {
|
|
85
|
+
const re = new RegExp(`(${query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
|
|
86
|
+
label = label.replace(re, chalk.yellow.bold('$1'));
|
|
87
|
+
}
|
|
88
|
+
return label;
|
|
89
|
+
}
|
|
90
|
+
/** Show an interactive browser task picker. */
|
|
91
|
+
export async function browserTaskPicker(config) {
|
|
92
|
+
const picked = await itemPicker({
|
|
93
|
+
message: config.message,
|
|
94
|
+
items: config.tasks,
|
|
95
|
+
filter: (query) => {
|
|
96
|
+
if (!query)
|
|
97
|
+
return config.tasks;
|
|
98
|
+
const q = query.toLowerCase();
|
|
99
|
+
return config.tasks.filter((t) => t.task.name.toLowerCase().includes(q) ||
|
|
100
|
+
t.profile.name.toLowerCase().includes(q) ||
|
|
101
|
+
t.task.domains?.some((d) => d.toLowerCase().includes(q)));
|
|
102
|
+
},
|
|
103
|
+
labelFor: buildBrowserLabel,
|
|
104
|
+
buildPreview: buildBrowserPreview,
|
|
105
|
+
shortIdFor: (t) => t.task.name,
|
|
106
|
+
pageSize: config.pageSize ?? 10,
|
|
107
|
+
initialSearch: config.initialSearch,
|
|
108
|
+
emptyMessage: 'No browser tasks running.',
|
|
109
|
+
enterHint: 'view tabs',
|
|
110
|
+
});
|
|
111
|
+
if (!picked)
|
|
112
|
+
return null;
|
|
113
|
+
return { task: picked.item, action: 'view' };
|
|
114
|
+
}
|