Skip to content

feat: add first-class CLI interaction modes#143

Open
nicknisi wants to merge 8 commits intomainfrom
nick/host-capability-probe
Open

feat: add first-class CLI interaction modes#143
nicknisi wants to merge 8 commits intomainfrom
nick/host-capability-probe

Conversation

@nicknisi
Copy link
Copy Markdown
Member

@nicknisi nicknisi commented May 4, 2026

Summary

  • Adds first-class interaction modes with global --mode human|agent|ci and WORKOS_MODE, while keeping --json scoped to output formatting.
  • Preserves compatibility for WORKOS_NO_PROMPT, non-TTY JSON defaults, and WORKOS_FORCE_TTY as an output-only override.
  • Surfaces interactionMode in workos doctor and runs host-execution probing for agent/CI mode so sandboxed runs are visible.
  • Migrates auth, login, install routing, API/env/config destructive flows, claim/debug behavior, and structured errors to branch on prompt/agent/CI semantics instead of JSON mode.
  • Adds recovery hints, agent/CI-specific guidance, machine-readable help metadata, and documentation for the two-axis model.

Why

Coding agents and CI need deterministic non-prompt behavior, but --json is only an output contract. Before this, output formatting, TTY detection, prompts, browser launches, and sandbox trust were coupled. That made pseudo-TTY agents and scripts hard to reason about and made host-sandbox failures look like real WorkOS configuration or auth failures.

This PR separates the two axes: output mode controls formatting; interaction mode controls who is driving the CLI and which behaviors are allowed.

Risk

  • Medium blast radius: this touches startup mode resolution plus auth/login/install/API/env/destructive command paths.
  • Compatibility-sensitive: non-TTY still defaults to agent interaction and JSON output, but WORKOS_FORCE_TTY now only forces human output, not human interaction. Use WORKOS_MODE=human for that.
  • Prompt behavior changes are intentional in agent/CI mode: missing args and destructive operations fail with structured guidance instead of prompting.
  • Main mitigation is broad unit coverage plus runtime smoke tests across inferred, explicit agent, explicit CI, explicit human + JSON, and help JSON modes.

Validation

  • pnpm test (138 files, 1776 tests)
  • pnpm typecheck
  • pnpm lint
  • pnpm format:check
  • pnpm build
  • pnpm exec tsx src/bin.ts doctor --json --skip-ai --skip-api --install-dir "$PWD" -> inferred agent / non_tty report; exits 1 here because this repo intentionally lacks WorkOS env vars
  • WORKOS_MODE=agent pnpm exec tsx src/bin.ts doctor --json --skip-ai --skip-api --install-dir "$PWD" -> agent / env
  • pnpm exec tsx src/bin.ts --mode agent doctor --json --skip-ai --skip-api --install-dir "$PWD" -> agent / flag
  • WORKOS_MODE=ci pnpm exec tsx src/bin.ts doctor --json --skip-ai --skip-api --install-dir "$PWD" -> ci / env
  • WORKOS_MODE=human pnpm exec tsx src/bin.ts doctor --json --skip-ai --skip-api --install-dir "$PWD" -> human / env, proving JSON output and interaction mode are separate
  • pnpm exec tsx src/bin.ts --mode agent doctor --help --json -> doctor command subtree

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a host-capability probe (home-fs, keychain) with per-session caching and gated warnings for non-interactive runs; emits reactive keychain-failure observations from credential/config stores and calls a proactive sandbox warning at authentication start. Includes Vitest tests for probe and warning semantics.

Changes

Sandbox & Host-Capability Detection

Layer / File(s) Summary
Core Types & Probe State
src/lib/host-probe.ts
Adds exported HostCapability, ProbeFailure, ProbeResult, module doc, imports, per-session state (warnedThisSession, cached probe), permission-detection regexes, and helper predicates.
Probe Implementations
src/lib/host-probe.ts
Adds probeHomeFs() (create/delete temp file under ~/.workos) and probeKeychain() (keyring Entry access; treats missing entry as non-failure).
Probe Aggregation & Caching
src/lib/host-probe.ts
Adds runHostProbe() to execute probes, collect failures, and cache the ProbeResult per session.
Warnings & Reactive Observation
src/lib/host-probe.ts
Adds warnIfSandboxed() to emit a single per-session warning in non-interactive environments when probes fail, observeHostFailure(capability,error) to emit targeted warnings on permission-like errors, and _resetProbeState() to clear cached state.
Integration: Keychain Failure Hooks
src/lib/config-store.ts, src/lib/credential-store.ts
Import observeHostFailure and call observeHostFailure('keychain', error) from keyring read/write catch blocks (in addition to existing warning logs).
Integration: Proactive Auth Warning
src/lib/ensure-auth.ts
Import warnIfSandboxed and invoke await warnIfSandboxed() at the start of ensureAuthenticated().
Tests
src/lib/host-probe.spec.ts
Adds Vitest suite that mocks fs, os.homedir, keyring, and environment interactivity; tests probe success/failure, missing-entry treatment, permission detection, caching, warn-once behavior, interactive gating, and observeHostFailure filtering and duplicate-warning prevention.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ⚠️ Warning The PR title 'feat: add first-class CLI interaction modes' does not accurately reflect the main changes, which focus on host-capability probes and sandbox detection. Update the title to more accurately describe the primary change, e.g., 'feat: add host-capability probes for sandboxed environments' as mentioned in the PR objectives.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch nick/host-capability-probe

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 4, 2026

Greptile Summary

This PR introduces host-capability diagnostics for sandboxed agent runs, a new interaction-mode abstraction (human/agent/ci), structured recovery hints, and a logVisibleWarn path that guarantees sandbox warnings reach stderr before the debug logger initialises.

  • Host probing: runHostProbe() checks ~/.workos write access and keychain reachability, emits a single logVisibleWarn per session via warnIfSandboxed(), and surfaces failures in workos doctor human and JSON output with a new HOST_EXECUTION_UNTRUSTED issue.
  • Interaction mode: resolveInteractionMode replaces the old ad-hoc TTY/env checks; WORKOS_FORCE_TTY now only controls output format, not interaction mode, which is an intentional and documented breaking change for that specific variable's scope.
  • Auth improvements: ensureAuthenticated calls warnIfSandboxed first and emits mode-specific error messages; exitWithAuthRequired automatically attaches agent-aware RecoveryHints to structured errors; extractHelpJsonCommand prevents --mode agent values from being mis-parsed as command names before yargs runs.

Confidence Score: 5/5

Safe to merge. All previously flagged issues with the host probe are addressed and the new interaction-mode system is well-tested.

The core host-probing logic correctly gates on isPermissionError for both home-fs and keychain paths. The interaction-mode abstraction cleanly replaces the old ad-hoc env-var checks and is covered by 135+ new tests.

src/lib/host-probe.ts — the isLikelyHostFailure function's unconditional true return for browser-launch and localhost-bind is worth a second look if false-positive sandbox warnings surface on headless Linux hosts in agent mode.

Important Files Changed

Filename Overview
src/lib/host-probe.ts New host capability probe module. Previous issues (require in ESM, missing isPermissionError gate on keychain probe) are addressed. Minor concern: isLikelyHostFailure unconditionally flags browser-launch and localhost-bind, diverging from the permission-only gate used for home-fs and keychain.
src/utils/interaction-mode.ts New interaction mode abstraction (human/agent/ci) with well-tested precedence chain. extractHelpJsonCommand prevents option values like 'agent' being mistaken for commands.
src/utils/debug.ts Adds logVisibleWarn which writes to stderr directly when debug is disabled, and goes through clack when debug is enabled — avoiding the silent-drop bug from the original sandbox warning path.
src/doctor/checks/auth-patterns.ts Adds isIgnoredSecretSourcePath to suppress API_KEY_IN_SOURCE findings in test/fixture/evals directories and .spec. / .test. files.
src/utils/recovery-hints.ts New structured recovery hints for auth_required, confirmation_required, and missing_args exits. Mode-aware hints (CI vs agent vs human) with hostShellRequired flag for agent-aware tooling.
src/bin.ts Sets interaction mode at startup from argv/env, adds --mode flag to yargs, and uses extractHelpJsonCommand to prevent option values being mis-parsed as command names before yargs runs.
src/lib/ensure-auth.ts Calls warnIfSandboxed before credential checks, and provides mode-specific auth failure messages (CI vs agent vs human) through the new exitForAuthRequired helper.

Reviews (9): Last reviewed commit: "Add first-class CLI interaction modes" | Re-trigger Greptile

greptile-apps[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

Comment thread src/lib/host-probe.ts
Comment on lines +61 to +64
} catch (error) {
const detail = error instanceof Error ? error.message : String(error);
return { capability: 'home-fs', detail };
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 probeHomeFs catches every exception and converts it to a ProbeFailure, so non-permission errors like ENOSPC (disk full) or EIO (I/O error on a network drive) will cause warnIfSandboxed to print "This may be a sandboxed environment." — which is wrong and confusing. observeHostFailure correctly gates on isPermissionError; probeHomeFs should do the same so the two paths stay consistent.

Suggested change
} catch (error) {
const detail = error instanceof Error ? error.message : String(error);
return { capability: 'home-fs', detail };
}
} catch (error) {
if (!isPermissionError(error)) return null;
const detail = error instanceof Error ? error.message : String(error);
return { capability: 'home-fs', detail };
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed in 7f9e0e6. probeHomeFs now mirrors observeHostFailure and only treats permission-class errors (isPermissionError) as sandbox indicators, so ENOSPC/EIO no longer produce misleading "sandboxed environment" warnings. Added a regression test (does not flag non-permission home-fs errors as sandbox failures).

devin-ai-integration[bot]

This comment was marked as resolved.

greptile-apps[bot]

This comment was marked as resolved.

nicknisi and others added 5 commits May 8, 2026 16:52
When the CLI runs inside an AI agent sandbox (Claude Code, Codex, Cursor),
the keyring and home directory may be unavailable. Instead of letting
opaque EPERM errors confuse the agent, we now:

1. Proactively probe home-fs and keychain on first auth check in
   non-interactive mode (warnIfSandboxed in ensure-auth)
2. Reactively observe permission errors in keyring read/write calls
   in both credential-store and config-store (observeHostFailure)
3. Emit a single actionable warning per session pointing the user
   to re-run on the host shell
- probeKeychain() no longer reports the keychain as failed when the
  probe entry is simply absent. A 'not found' / 'No such' error from
  @napi-rs/keyring now indicates a healthy keychain (matches the
  existing pattern in deleteFromKeyring in config-store and
  credential-store), so non-interactive runs on healthy hosts no longer
  emit false-positive sandbox warnings.
- Replace require('@napi-rs/keyring') with a static ES import. The
  package has 'type: module', so the previous require() threw
  ReferenceError at runtime and caused probeKeychain to always fail.
- Switch probeHomeFs to node:fs/promises and make runHostProbe and
  warnIfSandboxed async, per the project's no-sync-fs guideline.
- Tighten the /sandbox/i permission pattern to /\bsandboxd?\b/i so
  unrelated error messages containing 'sandbox' as a substring don't
  trigger sandbox warnings.

Updates the spec to drive the async API and adds coverage for the
healthy-keychain (entry-absent) and substring-collision cases.

Co-Authored-By: nick.nisi@workos.com <nick.nisi@workos.com>
Co-Authored-By: nick.nisi@workos.com <nick.nisi@workos.com>
probeHomeFs previously treated every fs error as a sandbox indicator,
so transient errors like ENOSPC or EIO would emit a misleading
"sandboxed environment" warning. Gate the catch block on
isPermissionError so it stays consistent with observeHostFailure.

Co-Authored-By: nick.nisi@workos.com <nick.nisi@workos.com>
probeKeychain previously treated any non-missing-entry keychain error
as a sandbox indicator. A user-canceled macOS keychain prompt or a
transient keyring daemon error would therefore produce a misleading
"sandboxed environment" warning on healthy hosts. Mirror probeHomeFs
and observeHostFailure by ignoring non-permission errors.

Co-Authored-By: nick.nisi@workos.com <nick.nisi@workos.com>
@nicknisi nicknisi force-pushed the nick/host-capability-probe branch from 1046ad3 to a9b122a Compare May 8, 2026 23:57
devin-ai-integration Bot and others added 2 commits May 9, 2026 00:12
Move fs.unlink into a finally block with best-effort error handling so
a successful writeFile never leaves an orphan probe file in ~/.workos
when unlink itself fails. The probe is checking write access; cleanup
should not affect the result.

Co-Authored-By: nick.nisi@workos.com <nick.nisi@workos.com>
@nicknisi nicknisi changed the title feat: add host-capability probes for sandboxed environments feat: add host execution diagnostics for sandboxed agents May 9, 2026
@nicknisi nicknisi changed the title feat: add host execution diagnostics for sandboxed agents feat: add first-class CLI interaction modes May 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant