setup: drop redundant agent ping; harden auth detection and OAuth paste

- verify: remove the CLI ping; cli-agent step earlier in setup already
  proved the round-trip works, and the test agent gets cleaned up before
  verify runs — so the ping was guaranteed to fail on installs that wired
  a messaging app instead of staying CLI-only. Status now collapses to
  service-running ∧ credentials ∧ ≥1 wired group.
- agent-ping: catch Claude Code's "Please run /login" / "Not logged in" /
  "Invalid API key" banners so a successfully-spawned agent that has no
  credentials no longer reports as 'ok'.
- auth paste: validate the full sk-ant-oat…AA shape; when the cleaned
  input is under 90 chars, surface a truncation-specific hint pointing at
  terminal wrap as the likely cause. Strip internal whitespace at both
  validate and assignment so multi-line pastes that survive clack also
  go through cleanly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
exe.dev user
2026-05-01 17:03:02 +00:00
parent 897b770296
commit 1b08b58fcd
5 changed files with 54 additions and 74 deletions

View File

@@ -14,7 +14,6 @@ import Database from 'better-sqlite3';
import { DATA_DIR } from '../src/config.js';
import { readEnvFile } from '../src/env.js';
import { log } from '../src/log.js';
import { pingCliAgent, type PingResult } from './lib/agent-ping.js';
import { getLaunchdLabel, getSystemdUnit } from '../src/install-slug.js';
import {
getPlatform,
@@ -33,11 +32,12 @@ export async function run(_args: string[]): Promise<void> {
// 1. Check service status + detect checkout mismatch.
//
// Why the mismatch matters: the host binds `<DATA_DIR>/cli.sock` relative
// to the project root it was started from. If the running service is from
// a sibling checkout (common for developers with multiple clones), this
// repo's `data/cli.sock` won't exist — AGENT_PING would return a
// misleading `socket_error`. Surface the mismatch directly instead.
// Why the mismatch matters: the host reads `<projectRoot>/data/v2.db` and
// binds `<DATA_DIR>/cli.sock` relative to the project root it was started
// from. If the running service is from a sibling checkout (common for
// developers with multiple clones), nothing in this checkout is actually
// wired up. Surface the mismatch directly so the user knows to point the
// service at the right folder.
let service:
| 'not_found'
| 'stopped'
@@ -186,7 +186,6 @@ export async function run(_args: string[]): Promise<void> {
if (has('IMESSAGE_ENABLED')) channelAuth.imessage = 'configured';
const configuredChannels = Object.keys(channelAuth);
const anyChannelConfigured = configuredChannels.length > 0;
// 5. Check registered groups in v2 central DB (agent_groups + messaging_group_agents)
let registeredGroups = 0;
@@ -218,23 +217,12 @@ export async function run(_args: string[]): Promise<void> {
mountAllowlist = 'configured';
}
// 7. End-to-end: ping the CLI agent and confirm it replies. Only run if
// everything upstream looks healthy, since a broken socket would just hang.
let agentPing: 'ok' | 'no_reply' | 'socket_error' | 'auth_error' | 'skipped' = 'skipped';
if (service === 'running' && registeredGroups > 0) {
log.info('Pinging CLI agent');
agentPing = await pingCliAgent();
log.info('Agent ping result', { agentPing });
}
// Determine overall status. A CLI-only install is valid when the local
// agent round-trip succeeds; messaging app credentials are optional.
// Determine overall status. The cli-agent step earlier in setup already
// proved the agent round-trip works; verify is a static health check.
const status = determineVerifyStatus({
service,
credentials,
anyChannelConfigured,
registeredGroups,
agentPing,
});
log.info('Verification complete', { status, channelAuth });
@@ -247,7 +235,6 @@ export async function run(_args: string[]): Promise<void> {
CHANNEL_AUTH: JSON.stringify(channelAuth),
REGISTERED_GROUPS: registeredGroups,
MOUNT_ALLOWLIST: mountAllowlist,
AGENT_PING: agentPing,
STATUS: status,
LOG: 'logs/setup.log',
});
@@ -258,18 +245,11 @@ export async function run(_args: string[]): Promise<void> {
export function determineVerifyStatus(input: {
service: 'not_found' | 'stopped' | 'running' | 'running_other_checkout';
credentials: string;
anyChannelConfigured: boolean;
registeredGroups: number;
agentPing: PingResult | 'skipped';
}): 'success' | 'failed' {
const cliAgentResponds = input.agentPing === 'ok';
const hasUsableChannel = input.anyChannelConfigured || cliAgentResponds;
return input.service === 'running' &&
input.credentials !== 'missing' &&
hasUsableChannel &&
input.registeredGroups > 0 &&
(cliAgentResponds || input.agentPing === 'skipped')
input.registeredGroups > 0
? 'success'
: 'failed';
}