When a command declares columns (e.g. ['rank', 'title', 'value']) but
returns an error row ({ error, help }), the declared columns would
render empty cells. Now resolveColumns detects the error key and falls
back to the row's actual keys, making diagnostics visible in all output
formats.
- slock: agents, channels, messages, servers now use getSlockContext/resolveChannelId
from utils.ts; error handling uses { error, help } return instead of bare throws
- linux-do: export fetchLinuxDoJson from feed.ts; migrate search, topic, categories,
tags, user-posts, user-topics from pipeline+throw to func() using fetchLinuxDoJson
- xueqiu: add utils.ts with fetchXueqiuJson helper; migrate hot, feed, search, stock,
watchlist, hot-stock, groups, kline, earnings-date from pipeline+throw to func()
* docs(skills): unify browser tool names to `opencli browser` commands
Replace abstract MCP tool names (browser_navigate, browser_snapshot,
browser_network_requests, browser_click, browser_evaluate) with
concrete `opencli browser` CLI commands in explorer and oneshot skills.
This aligns all three browser-related skills into a clear hierarchy:
- opencli-browser: atomic command reference
- opencli-oneshot: 4-step quick generation workflow
- opencli-explorer: full site exploration workflow
* docs(skills): address review — demote explore, fix eval placeholder
1. Demote `opencli explore` from "recommended" to "supplementary helper"
and make `opencli browser` the explicit primary path for API discovery.
2. Fix `url` undefined variable in eval example — use `<API URL>` placeholder.
* feat: auto-close adapter windows, add OPENCLI_WINDOW_FOCUSED, document config
1. Adapter commands now close the automation window immediately after
completion instead of waiting for the 30s idle timeout.
2. OPENCLI_WINDOW_FOCUSED=1 opens automation windows in the foreground
(useful for debugging). Default remains background.
3. Add Configuration section to README (EN/ZH) and opencli-usage skill
listing all stable user-facing environment variables.
* Fix OPENCLI_WINDOW_FOCUSED to be per-request, not frozen at daemon startup
Move env var read from daemon (startup-time constant) to CLI side
(sendCommandRaw), so it works correctly with the persistent daemon model.
Each request now reads the env var fresh and includes windowFocused in
the command payload.
* fix(xiaoe): resolve missing episodes for long courses by handling lazy load
* fix(xiaoe): keep lazy-load scroll until inner list stabilizes
---------
Co-authored-by: jackwener <jakevingoo@gmail.com>
* refactor: make daemon persistent, remove idle timeout
- Remove IdleManager and 4-hour idle auto-exit
- Daemon now stays alive until explicit shutdown or uninstall
- Add preuninstall hook for best-effort daemon cleanup on npm uninstall
- Update docs to reflect persistent daemon model
* fix: remove stale idle timeout references from code and docs
* refactor: remove daemon status/restart commands and lastCliRequestTime
- Remove `daemon status` and `daemon restart` CLI commands (doctor covers diagnostics)
- Remove `lastCliRequestTime` tracking (no longer needed without idle timeout)
- Keep only `daemon stop` as the explicit shutdown command
* Add AbortSignal.timeout(3s) to preuninstall shutdown fetch
Prevents npm uninstall from hanging if the daemon port accepts
connections but never responds.
* refactor: unify browser error classification and deduplicate retry logic
Replace two overlapping error classification systems with a single
classifyBrowserError() that returns retry advice (retryable + delayMs):
- Extension/daemon transient errors → retryable, 1500ms delay
- CDP target navigation errors → retryable, 200ms delay
- Non-transient errors → not retryable
Deduplicate sendCommand/sendCommandFull retry loop into sendCommandRaw,
making both public functions thin return-value wrappers.
* fix: add error kind to prevent page-level retry of extension errors
classifyBrowserError() now returns a `kind` field:
- extension-transient: retried by daemon-client only
- target-navigation: retried by page-level settle logic
- non-retryable: no retry
Page.goto() and Page.evaluate() now only settle-retry on
target-navigation, preventing extension/daemon errors from being
silently swallowed as settle noise.
Use Chrome CDP targetId (UUID) as the canonical page identity across
all layers (extension → daemon → CLI), demoting tabId to an
extension-internal routing detail.
- Add extension/src/identity.ts: bidirectional targetId ↔ tabId mapping
with lazy refresh via chrome.debugger.getTargets()
- Update protocol: Command.page and Result.page carry targetId
- Update background.ts: resolveCommandTabId() and pageScopedResult()
helpers; all page-scoped handlers return targetId
- Add sendCommandFull() to daemon-client for responses with page identity
- Update Page class: _page stores targetId, goto/selectTab extract it
- Update record.ts: injectedPages tracks by targetId
- Add extension tests to vitest config and CI test scripts
Synced all desktop adapter command lists in desktop.md with
the actual `opencli <adapter> --help` output:
- cursor: remove non-existent status/new/dump/screenshot; add composer
- codex: remove non-existent status/new/dump/screenshot
- chatgpt: add missing model command
- chatwise: remove non-existent new/screenshot
- notion: update descriptions to match help text
- discord-app: update descriptions to match help text
- doubao-app: reorder to match help output
- antigravity: remove non-existent ask; add serve/status
Also moved `status` to the top of each adapter section where it exists.
* perf: fast-path completion, version, and shell scripts to bypass full discovery
Lightweight commands (--get-completions, --version, completion <shell>) now
resolve before any heavy module loading. Key changes:
- New completion-fast.ts: manifest-based completion + shell script generators
with zero dependency on registry/discovery/cli modules
- main.ts: static imports replaced with dynamic import() for the full startup
path so the fast path never pays the cost of loading discovery, registry,
Commander, hooks, etc.
- USER_CLIS_DIR inlined to avoid importing the entire discovery module
- completion.ts: removed manifest functions (moved to completion-fast.ts),
now only used as fallback when manifest is unavailable
* fix: address review blockers from codex-mini0
1. --version fast path: only match when argv[0] is --version/-V,
not anywhere in argv. Prevents intercepting `opencli gh --version`
which should pass through to the subcommand.
2. Completion fast path: require ALL manifests to exist (hasAllManifests),
not just one. If user clis dir exists but has no manifest, fall back
to full discovery so user adapters aren't silently dropped.
If user clis dir doesn't exist at all, skip its manifest requirement
since there are no user adapters to miss.
EMPTY_RESULT and structurally-valid SELECTOR failures are often not
adapter bugs — they're the platform shaping results under anti-scrape,
or a soft 404, or a legitimately empty search. Patching a working
adapter to chase a zero-result query breaks the next working path.
Add a pre-check section at the top of opencli-autofix listing four
rule-outs that must fail before a repair round is justified:
1. Retry with an alternative query / entry point
2. Spot-check the page in a normal Chrome tab
3. Look for soft 404s (200 with empty payload)
4. Remember that "0 results" from a search is a valid answer
Placed directly before "Step 1: Collect Diagnostic Context" so the
check runs at exactly the moment the agent would otherwise commit to
a repair round.
Audience/timing is the whole point: the skill is loaded precisely when
an error has occurred and the agent is deciding whether to repair, and
the pre-check intercepts that decision before it locks in.
11 lines of markdown, zero code, single file.
---
Inspired by https://github.com/eze-is/web-access by 一泽 Eze (MIT),
specifically the "平台返回的'内容不存在'不一定反映真实状态" mental model
from its SKILL.md. Adapted into concrete, actionable checks for
opencli's EMPTY_RESULT classification.
Note: an earlier version of this PR also added a tool-selection
decision table and a subagent-verb rule to opencli-usage. Both were
removed after review because opencli-usage only loads *after* an agent
has committed to using opencli — advice placed there arrives too late
to change tool selection, and is not seen by the main agent at
delegation time. The insights are still valid; they just don't have a
load-time match in the current skill system. This PR keeps only the
change where audience and timing actually line up.
* refactor(skills): unify command reference by site instead of technology
- Merge Browser-based and Public API sections into single alphabetical
table with type emoji tags (🌐/✅/🖥️/🔧)
- Delete browser.md and public-api.md (replaced by unified SKILL.md table)
- Add GitHub/DevOps and collaboration rows to capability lookup
- Remove stale File column from capability table
* feat(skills): add commands.md with merged examples + 8 missing adapters
- Create commands.md: merge browser.md + public-api.md into single
alphabetical-by-site reference with detailed usage examples
- Add 8 missing adapters: 1688, hupu, jianyu, lesswrong, quark,
xianyu, xiaoe, yuanbao
- Bump skill version 1.6.3 → 1.6.9 to match package.json
- Add dedicated External CLI section listing all 7 registered CLIs
(gh, obsidian, docker, lark-cli, dws, wecom-cli, vercel)
- Include install/register commands so AI agents know how to manage them
- Move gh from Desktop to External CLI section
- Update desktop.md to remove gh and reference External CLI section
* refactor(skills): merge opencli-generate into opencli-explorer
opencli-generate was a thin wrapper over generateVerifiedFromUrl,
essentially an internal pipeline orchestration. Merge its entry point
into opencli-explorer as the automated fast path, keeping one unified
skill for adapter creation.
- Delete skills/opencli-generate/SKILL.md
- Add automated generation tip to opencli-explorer SKILL.md
- Update README/README.zh-CN skill references
- Update skill-generate.ts comment
* fix(docs): fix dead link in yaml-adapter deprecation page
Change ../../CONTRIBUTING.md to ./contributing (VitePress internal link).
* refactor: remove version field from GenerateOutcome and EarlyHint
All consumers are in the same repo and evolve together — version field
adds ceremony without practical value at this stage.
Keeps schema_version in VerifiedArtifactMetadata (sidecar file format).
* refactor: migrate all 123 CLI adapters from YAML to TypeScript
Remove YAML as an adapter format entirely. All adapters now use
TypeScript with cli() from @jackwener/opencli/registry.
- Convert 123 YAML adapter files to TypeScript via batch script
- Remove YAML scanning from discovery.ts (registerYamlCli, yaml import)
- Remove scanYaml() and shouldReplaceManifestEntry() from build-manifest.ts
- Change synthesize.ts to output JSON candidates (internal format)
- Change generate-verified.ts to write .ts adapter files instead of .yaml
- Delete yaml-schema.ts (dead code) and scripts/yaml-to-ts.mjs (one-time tool)
- Update all tests to match new format
Closes discussion in #OpenCLI thread 47ddba82.
* fix: close YAML migration gaps in plugin scaffold, validation, and scan
- plugin-scaffold.ts: generate hello.ts (TS pipeline) instead of hello.yaml
- plugin.ts validatePluginStructure: no longer accept .yaml as valid command file
- plugin.ts scanPluginCommands: remove .yaml/.yml from scanned extensions
- discovery.ts: add explicit log.warn() when YAML files detected in clis/ or plugins/
- plugin.test.ts: update all test fixtures from .yaml to .js
- plugin-scaffold.test.ts: update hello.yaml references to hello.ts
- Delete dead src/yaml-schema.ts
Resolves PR #887 review blockers from @mbp-codex-pr0.
* refactor: complete YAML removal across docs, skills, record, and binance adapters
Code changes:
- record.ts: candidate output changed from .yaml (yaml.dump) to .json (JSON.stringify), removed js-yaml import
- src/clis/binance: convert all 11 YAML adapters to TypeScript cli() format
- binance/commands.test.ts: rewrite to use registry instead of yaml.load
- skill-generate.test.ts, diagnostic.test.ts: update mock paths from .yaml to .ts
- build-manifest.ts, synthesize.ts: update stale YAML comments
Documentation:
- README.md: remove .yaml from Dynamic Loader, fix plugin types, fix synthesize comment
- README.zh-CN.md: fix synthesize comment
- CONTRIBUTING.md: replace YAML Adapter section with Pipeline Adapter (TS), update arg examples
- docs/developer/yaml-adapter.md: replaced with deprecation redirect
- docs/developer/architecture.md: remove YAML pipeline references
- docs/developer/contributing.md: remove YAML adapter section
- docs/developer/ai-workflow.md: YAML → TS in synthesize description
- docs/guide/getting-started.md: remove .yaml from loader, update engine description
- docs/guide/plugins.md: remove YAML plugin option, update plugin types
- docs/index.md, docs/comparison.md: remove YAML adapter references
- docs/zh/guide/plugins.md: remove .yaml from scan description
Skills:
- opencli-explorer/SKILL.md: rewrite YAML vs TS decision tree to TS-only
- opencli-oneshot/SKILL.md: replace YAML templates with TS cli() templates
- opencli-generate/SKILL.md: YAML artifact path → TS artifact path
- opencli-usage/SKILL.md, plugins.md: update adapter format references
* fix: clean up remaining YAML adapter references in docs
- docs/zh/guide/plugins.md: replace YAML plugin example with TS pipeline
- docs/developer/testing.md: YAML Adapter heading → Adapter, remove validate line
- TESTING.md: same fix in root testing doc
- CONTRIBUTING.md: remove "YAML validation" comment
- docs/.vitepress/config.mts: mark YAML Adapter Guide as (Deprecated) in nav
- docs/advanced/download.md: remove "YAML Adapters" from pipeline step heading
All consumers are in the same repo and evolve together — version field
adds ceremony without practical value at this stage.
Keeps schema_version in VerifiedArtifactMetadata (sidecar file format).
* fix: use Strategy.PUBLIC enum in skill-generate test to fix typecheck regression
* feat: add P2 EarlyHint callback channel to generateVerifiedFromUrl
Add optional onEarlyHint callback for internal cost gating before verify stage.
- EarlyHint type: version, stage, continue, reason, confidence, candidate?
- 3 emit points: explore (viable/not), synthesize (candidate/not), cascade (auth/ok)
- candidate only on synthesize/cascade + continue:true (not on stop or explore)
- unsupported-required-args goes directly to P1 terminal, no P2 hint emitted
- 6 new tests covering all hint paths + guardrails
* docs: add opencli-generate skill spec (SKILL.md)
Captures A+B consensus from team discussion:
- Input: url + goal? (natural language intent hint)
- Output: SkillOutput with machine-readable fields + human message
- Decision tree: thin mapping from GenerateOutcome
- Guardrails: no re-orchestration, no auto-escalation, no new taxonomy
- P1/P2 boundary: P1 is single source of truth, P2 transparent to skill
* fix: address review nits on skill spec
- Make path explicitly optional in needs-human-check decision tree
- Add missing non-array-result message template
* feat: add GenerateOutcome → SkillOutput thin wrapper
Implements the skill mapping layer per opencli-generate SKILL.md:
- mapOutcomeToSkillOutput: thin translation from P1 contract to agent-facing output
- executeGenerateSkill: entry point accepting SkillInput (url + goal?)
- Message templates for all StopReason and EscalationReason values
- 8 tests covering all outcome paths and contract shape validation
* fix: prefer outcome.message for richer context in needs-human-check
When GenerateOutcome has a message (e.g. "required args: id"), use it
instead of the generic template, so the specific args info reaches the user.
All 68 browser adapter links and 8 desktop adapter links in
docs/adapters/index.md were missing the .md file extension,
causing broken links when navigating the documentation on GitHub.