From a1560fb0f5f212b59290acd1a9b4ae9bb136e18c Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Sat, 20 Jun 2026 13:28:35 +0900 Subject: [PATCH] Fix misleading npx hints in live-mode poll/wrap scripts (#275) * Replace npx hints in live scripts with bundled-script paths The live-mode poll/wrap scripts are invoked by the agent via `node {{scripts_path}}/live-*.mjs`, never through the `npx impeccable` CLI. Their help text and runtime error hints still pointed at `npx impeccable poll|live|wrap`, which is misleading and, for the error paths, not directly runnable. - Docstrings/comments (never executed): switch to the `node /...` convention already used by live-server.mjs. - Runtime-printed error/usage strings: resolve the script's own dir via import.meta.url and print a real, copy-pasteable absolute path instead of a placeholder. Verified by triggering the error paths from the synced bundle and by running the live-mode E2E (vite8-react-modal) through the full cycle. Co-Authored-By: Claude Opus 4.8 (1M context) * Quote script paths in runtime hints to handle spaces Paths containing spaces (e.g. /Users/john doe/...) would otherwise produce a non-runnable command. Addresses Greptile review feedback. Co-Authored-By: Claude Opus 4.8 (1M context) --------- Co-authored-by: Claude Opus 4.8 (1M context) --- skill/scripts/live-poll.mjs | 27 ++++++++++++++++----------- skill/scripts/live-wrap.mjs | 2 +- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/skill/scripts/live-poll.mjs b/skill/scripts/live-poll.mjs index b031055fe..740161e10 100644 --- a/skill/scripts/live-poll.mjs +++ b/skill/scripts/live-poll.mjs @@ -2,11 +2,11 @@ * CLI client for the live variant mode poll/reply protocol. * * Usage: - * npx impeccable poll # Block until browser event, print JSON - * npx impeccable poll --stream # Experimental: keep polling; one JSON line per event - * npx impeccable poll --timeout=600000 # Custom timeout (ms); default is long-poll friendly - * npx impeccable poll --reply done # Reply "done" to event - * npx impeccable poll --reply error "msg" # Reply with error + * node /live-poll.mjs # Block until browser event, print JSON + * node /live-poll.mjs --stream # Experimental: keep polling; one JSON line per event + * node /live-poll.mjs --timeout=600000 # Custom timeout (ms); default is long-poll friendly + * node /live-poll.mjs --reply done # Reply "done" to event + * node /live-poll.mjs --reply error "msg" # Reply with error */ import { execFileSync } from 'node:child_process'; @@ -15,6 +15,11 @@ import { fileURLToPath } from 'node:url'; import { completionAckForAcceptResult, completionTypeForAcceptResult } from './live/completion.mjs'; import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; +// Absolute path to a sibling script in this skill's scripts dir, so runtime +// error hints print a directly-runnable command instead of a placeholder. +const SELF_DIR = path.dirname(fileURLToPath(import.meta.url)); +const scriptCmd = (name) => `node "${path.join(SELF_DIR, name)}"`; + // Node's built-in fetch (undici under the hood) enforces a 300s headers // timeout that can't be lowered per-request. We cap each request below // that ceiling and loop in `pollOnce` to synthesize a long poll without @@ -27,7 +32,7 @@ const EVENT_TYPES_NEEDING_AGENT_REPLY = new Set(['generate', 'steer', 'manual_ed function readServerInfo() { const record = readLiveServerInfo(process.cwd()); if (!record) { - console.error('No running live server found. Start one with: npx impeccable live'); + console.error(`No running live server found. Start one with: ${scriptCmd('live.mjs')}`); process.exit(1); } return record.info; @@ -82,7 +87,7 @@ export function parseReplyArgs(args) { } function validateReplyArgs({ id, status }) { - const usage = "Usage: npx impeccable poll --reply [--file path] [--data ''] [message]"; + const usage = `Usage: ${scriptCmd('live-poll.mjs')} --reply [--file path] [--data ''] [message]`; if (!id || id.startsWith('--')) { const err = new Error(`${usage}\nMissing event id after --reply.`); err.code = 'INVALID_REPLY_ARGS'; @@ -283,11 +288,11 @@ export async function runPollStream(base, token, { function handlePollError(err) { if (err.code === 'AUTH_FAILED') { console.error(err.message); - console.error('Try restarting: npx impeccable live stop && npx impeccable live'); + console.error(`Try restarting: ${scriptCmd('live-server.mjs')} stop && ${scriptCmd('live.mjs')}`); process.exit(1); } if (err.cause?.code === 'ECONNREFUSED') { - console.error('Live server not running. Start one with: npx impeccable live'); + console.error(`Live server not running. Start one with: ${scriptCmd('live.mjs')}`); process.exit(1); } if (err.code === 'ACK_TIMEOUT') { @@ -331,7 +336,7 @@ Harness note: const info = readServerInfo(); const base = `http://localhost:${info.port}`; - // Reply mode: npx impeccable poll --reply [--file path] [--data ''] [message] + // Reply mode: node /live-poll.mjs --reply [--file path] [--data ''] [message] if (args.includes('--reply')) { let reply; try { @@ -345,7 +350,7 @@ Harness note: await postReply(base, info.token, reply); } catch (err) { if (err.cause?.code === 'ECONNREFUSED') { - console.error('Live server not running. Start one with: npx impeccable live'); + console.error(`Live server not running. Start one with: ${scriptCmd('live.mjs')}`); } else { console.error('Reply failed:', err.message); } diff --git a/skill/scripts/live-wrap.mjs b/skill/scripts/live-wrap.mjs index c3f00f3a4..438c01b68 100644 --- a/skill/scripts/live-wrap.mjs +++ b/skill/scripts/live-wrap.mjs @@ -2,7 +2,7 @@ * CLI helper: find an element in source and wrap it in a variant container. * * Usage: - * npx impeccable wrap --id SESSION_ID --count N --query "hero-combined-left" [--file path] + * node /live-wrap.mjs --id SESSION_ID --count N --query "hero-combined-left" [--file path] * * Searches project files for the element matching the query (class name, ID, or * text snippet), wraps it with the variant scaffolding, and prints the file path