-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Comparing changes
Open a pull request
base repository: jackwener/OpenCLI
base: v1.5.0
head repository: jackwener/OpenCLI
compare: v1.5.1
- 18 commits
- 37 files changed
- 5 contributors
Commits on Mar 27, 2026
-
fix(doctor): remove unused fix option and add release URL to extensio…
…n install hint (#498) * feat: zero onboarding, extension version check, and update notifier - Fail-fast guard in execution.ts: when daemon is running but extension is not connected, immediately surface a setup guide instead of waiting for the 30s connect timeout - Extension version handshake: extension sends `hello` with its version on WebSocket connect; daemon stores it and exposes via /status; CLI warns on mismatch in both execution path and `opencli doctor` - `opencli doctor` now shows extension version inline and reports version mismatch as an actionable issue - Non-blocking npm update checker: registers a process exit hook so the update notice appears after command output (same pattern as npm/gh/yarn); background fetch writes to ~/.opencli/update-check.json for next run - postinstall: print Browser Bridge setup instructions after shell completion install for first-time global install users Bug fixes caught in review: - discover.ts: add AbortController timeout to checkDaemonStatus() fetch, move clearTimeout after res.json() to cover body streaming - daemon.ts: clear extensionVersion and reject pending requests in ws.on('error') handler, not just ws.on('close') - update-check.ts: skip update notice when process exits with non-zero code; read cache once at module load to avoid double disk I/O; guard isNewer() against NaN from pre-release version strings * fix: reduce fail-fast timeout to 300ms and guard stderr.write in exit hook * fix(doctor): remove unused fix option and add release URL to extension install hint * fix(e2e): update BrowserBridge unavailable detection regex to match current error format
Configuration menu - View commit details
-
Copy full SHA for f9f018d - Browse repository at this point
Copy the full SHA f9f018dView commit details -
fix(plugin): remove legacy LOCK_FILE/MONOREPOS_DIR constants (#495)
Remove the module-level LOCK_FILE and MONOREPOS_DIR constants that were computed at load time using os.homedir(). These ignored the HOME environment variable, causing path mismatches when tests use HOME for isolation. All usages now go through getLockFilePath() and getMonoreposDir() which respect process.env.HOME. Updated plugin.test.ts accordingly.
Configuration menu - View commit details
-
Copy full SHA for d742635 - Browse repository at this point
Copy the full SHA d742635View commit details -
feat(plugin): add 'plugin create <name>' scaffold command (#494)
* feat(plugin): add 'plugin create <name>' scaffold command Generate a ready-to-develop plugin directory with all required files: - opencli-plugin.json (manifest with name, version, compatibility) - package.json (ESM, peer dependency on @jackwener/opencli) - hello.yaml (sample YAML command using httpbin) - greet.ts (sample TS command using cli() API) - README.md (install, usage, and development instructions) Usage: opencli plugin create my-plugin opencli plugin create my-plugin --dir /path/to/dir opencli plugin create my-plugin --description 'My awesome plugin' Includes 5 test cases for scaffold generation and error handling. * fix(plugin): align scaffold with local install flow --------- Co-authored-by: jackwener <jakevingoo@gmail.com>
Configuration menu - View commit details
-
Copy full SHA for fa4c44a - Browse repository at this point
Copy the full SHA fa4c44aView commit details -
feat(plugin): support local path install via file:// and absolute path (
#491) Add support for installing plugins from local directories: opencli plugin install file:///path/to/my-plugin opencli plugin install /path/to/my-plugin Local plugins are symlinked (not copied) into ~/.opencli/plugins/ so code changes are reflected immediately without reinstall — ideal for plugin development workflows. Changes: - parseSource() now handles file:// URLs and bare absolute paths - New installLocalPlugin() creates symlink + installs deps + transpiles - Lock file records 'local:<path>' as source for local plugins - 6 new test cases for local path parsing and install behavior
Configuration menu - View commit details
-
Copy full SHA for 384419f - Browse repository at this point
Copy the full SHA 384419fView commit details -
fix(xiaohongshu): adapt publish to new two-step creator center UI (#490)
* fix(xiaohongshu): adapt publish to new two-step creator center UI (#460) The creator center now requires image upload before showing the title/content editor form. This caused the publish command to fail with "Could not find title input". - Add waitForEditForm() to poll for editor after image upload - Extract TITLE_SELECTORS constant shared by waitForEditForm and fillField - Add contenteditable title selectors for new UI - Make images required (new UI mandates images before editor) - Update draft button to match both '暂存离开' and '存草稿' - Exclude title placeholder from content fallback selector - Update tests to match new flow * refactor(xiaohongshu): clarify publish surface states --------- Co-authored-by: jackwener <jakevingoo@gmail.com>
Configuration menu - View commit details
-
Copy full SHA for 39eec0d - Browse repository at this point
Copy the full SHA 39eec0dView commit details -
fix(plugin): detect symlinked monorepo sub-plugins in discoverPlugins (…
…#487) * fix(plugin): detect symlinked monorepo sub-plugins in discoverPlugins discoverPlugins() used entry.isDirectory() to filter plugin directories, but monorepo sub-plugins are installed as symlinks pointing into ~/.opencli/monorepos/. On most Node.js versions, isDirectory() returns false for symlinks, causing monorepo plugin commands to be silently skipped during discovery. Add entry.isSymbolicLink() check so symlinked plugin directories are properly discovered and their commands registered. * fix(plugin): skip broken symlink discovery --------- Co-authored-by: jackwener <jakevingoo@gmail.com>
Configuration menu - View commit details
-
Copy full SHA for 5e2e1df - Browse repository at this point
Copy the full SHA 5e2e1dfView commit details -
fix(twitter): use DOM-only scraping for trending to match page results (
Configuration menu - View commit details
-
Copy full SHA for fb5b608 - Browse repository at this point
Copy the full SHA fb5b608View commit details -
perf: parallel file discovery, plugin scanning, and external CLI cach…
…ing (#501) - Parallelize file scanning in discoverClisFromFs and discoverPluginDir using Promise.all(files.map(async ...)) instead of serial for-of with await, so isCliModule checks run concurrently - Parallelize plugin directory scanning in discoverPlugins - Cache loadExternalClis() result to avoid re-parsing YAML on every call - Invalidate cache in registerExternalCli after writing to disk - Cache strategyLabel() call in list command to avoid redundant computation - Add comment explaining why discovery must remain sequential (plugin override semantics)
Configuration menu - View commit details
-
Copy full SHA for 31cb229 - Browse repository at this point
Copy the full SHA 31cb229View commit details -
feat(xiaohongshu): add published_at to search results (#484) (#485)
Derive approximate publish date from note IDs, which follow MongoDB ObjectID format (first 8 hex chars = Unix timestamp). Exported as a pure function with UTC+8 offset for China timezone. Closes #484
Configuration menu - View commit details
-
Copy full SHA for 1a44d8c - Browse repository at this point
Copy the full SHA 1a44d8cView commit details -
fix(plugin): handle EXDEV cross-filesystem rename during install (#488)
* fix(plugin): handle EXDEV cross-filesystem rename during install fs.renameSync() fails with EXDEV when source and destination are on different filesystem mount points. This commonly happens because plugin clones land in os.tmpdir() (often /tmp on a tmpfs) while plugins are installed to ~/.opencli/plugins/ (on the root filesystem). Add a moveDir() helper that catches EXDEV and falls back to fs.cpSync() + fs.rmSync(). Applied to both single-plugin and monorepo install paths. * review: clean up failed EXDEV fallback installs --------- Co-authored-by: jackwener <jakevingoo@gmail.com>
Configuration menu - View commit details
-
Copy full SHA for 55d0473 - Browse repository at this point
Copy the full SHA 55d0473View commit details -
feat(bluesky): add Bluesky adapter with 9 commands (#215)
Bluesky (9 commands, public AT Protocol API, no auth needed): - profile: user profile info (followers, following, posts) - user: recent posts from a user with engagement stats - trending: trending topics on Bluesky - search: search users - feeds: popular feed generators - followers: list user's followers - following: list accounts a user follows - thread: post thread with replies - starter-packs: user's starter packs All commands use the public Bluesky API, no browser or login required.
Configuration menu - View commit details
-
Copy full SHA for 9a9e078 - Browse repository at this point
Copy the full SHA 9a9e078View commit details -
fix(execution): apply timeout to non-browser commands (#383)
Non-browser commands (`browser: false`) ran without any timeout protection, even when `timeoutSeconds` was explicitly set. This wraps the non-browser execution path with `runWithTimeout()` when the adapter defines a positive `timeoutSeconds`. Also adds an optional `hint` parameter to `TimeoutError` so the non-browser path shows a relevant suggestion instead of the browser-specific `OPENCLI_BROWSER_COMMAND_TIMEOUT` env var hint.
Configuration menu - View commit details
-
Copy full SHA for ee59750 - Browse repository at this point
Copy the full SHA ee59750View commit details -
fix(plugin): prevent raw .ts import crash when esbuild transpilation …
…fails (#500) (#503) When a TS plugin is installed but esbuild is unavailable or transpilation fails silently, the plugin discovery would attempt to import() the raw .ts file, causing 'Unknown file extension .ts' on production Node.js. Changes: - discovery.ts: Skip raw .ts import when no compiled .js exists; show an actionable warning guiding the user to re-transpile or install esbuild - plugin.ts: Upgrade esbuild-not-found from debug to warn level; log the outer catch error instead of silently swallowing it Closes #500
Configuration menu - View commit details
-
Copy full SHA for 2ad1215 - Browse repository at this point
Copy the full SHA 2ad1215View commit details -
feat(plugin): support multi-source plugin install (ssh, git@, generic…
… https) (#504) Extends parseSource() to accept any git-cloneable URL, not just GitHub: - ssh://git@host/path/repo.git - git@host:user/repo.git (SCP-style) - https://any-host.com/path/repo.git GitHub shorthand (github:user/repo) and local paths continue to work. Updated error messages, CLI description, docs, and added 7 new unit tests. Closes #492
Configuration menu - View commit details
-
Copy full SHA for 70ad570 - Browse repository at this point
Copy the full SHA 70ad570View commit details -
perf: smart pre-navigation — skip redundant nav + remove 2s wait (#507)
* perf: smart pre-navigation — skip redundant domain nav + remove hardcoded 2s wait - Add `getCurrentUrl()` to IPage, Page, and CDPPage to check current browser URL - Skip pre-navigation entirely if the browser is already on the target domain - Remove the hardcoded `page.wait(2)` after pre-navigation — `page.goto()` already includes smart DOM-settle detection via `waitForDomStable`, making the fixed 2-second sleep redundant - Saves ~2s per browser command in the common case (consecutive commands on the same site), and ~1-2s even on cold navigation * perf: smart page.wait() — DOM-stable early return for waits >= 1s For page.wait(N) where N >= 1 second, use DOM MutationObserver-based stability detection instead of a fixed sleep. The original wait time becomes a hard cap, but the call returns as soon as the DOM stops mutating (500ms quiet period). This benefits ~200 hardcoded sleep calls across ~40 adapters without changing any adapter code. A typical page.wait(5) now completes in <1s when the page is already stable, instead of always waiting 5s. Short waits (< 1s) are kept as fixed sleeps — these are typically UI animation delays or anti-bot throttling where DOM-ready is irrelevant. * refactor: getCurrentUrl() uses in-memory tracking instead of round-trip Replace the sendCommand('exec', 'window.location.href') call with a local _lastUrl field set during goto(). This eliminates a daemon HTTP round-trip for the domain check, making isAlreadyOnDomain() zero-cost. On fresh tabs (about:blank), _lastUrl is null so we correctly fall through to navigation — no special-casing needed.Configuration menu - View commit details
-
Copy full SHA for cf99c61 - Browse repository at this point
Copy the full SHA cf99c61View commit details -
fix(v2ex): fetch hot topics through browser context (#493)
* Update hot.yaml * review: fetch v2ex hot data within browser context --------- Co-authored-by: jackwener <jakevingoo@gmail.com>
Configuration menu - View commit details
-
Copy full SHA for a2d1199 - Browse repository at this point
Copy the full SHA a2d1199View commit details -
refactor(plugin): make plugin installs transactional (#509)
* feat(plugin): stage installs before promote * feat(plugin): make remote updates transactional * fix(plugin): rollback relink failures * refactor(plugin): unify transactional publish flow * refactor(plugin): extract publish pipeline helpers * refactor(plugin): add structured source model * refactor(plugin): promote lockfile to structured sources * fix(plugin): preserve lock reads when migration rewrite fails * fix(plugin): write lockfiles atomically * test(plugin): make source helper assertions cross-platform
Configuration menu - View commit details
-
Copy full SHA for 5bd0497 - Browse repository at this point
Copy the full SHA 5bd0497View commit details -
Configuration menu - View commit details
-
Copy full SHA for f9f11e4 - Browse repository at this point
Copy the full SHA f9f11e4View commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff v1.5.0...v1.5.1