Picker copy follow-ups: raw rows name the listener, openclaw names the restart, claude-desktop reassurance - #647
Picker copy follow-ups: raw rows name the listener, openclaw names the restart, claude-desktop reassurance#647philcunliffe wants to merge 2 commits into
Conversation
…e restart, claude-desktop reassurance Three picker rows changed the machine without saying so in the one place the user reads before choosing. - raw-anthropic / raw-openai set compose.requires_gateway, which composes @hypaware/ai-gateway and binds an HTTP listener on 127.0.0.1 (default 127.0.0.1:18521). The otel row already names its receiver; these two named nothing, and they carry no adapter to disclose it elsewhere. - openclaw's summary named the config rewrite but not the manual 'openclaw gateway restart' that makes it take effect. attach.js prints that only after the config is already rewritten. - claude-desktop lost its "asks before changing anything" reassurance in the copy shortening. Its machine change is behind needs_setup + configure_command 'claude-desktop install', which explains and asks, defaulting to no (LLP 0139#informed-consent), so the reassurance was accurate. Each new clause is pinned in test/plugins/picker-disclosure.test.js by substance rather than exact wording, so a future shortening pass fails instead of silently dropping the disclosure again. Fixes #637 Co-Authored-By: Claude <noreply@anthropic.com>
…tener, restart command pinned to source Review of #647 found two LOW issues: - The PR named hermes as the remaining requires_gateway row left out of scope, which is backwards. hermes sets requires_gateway with no gateway_upstream, so picked alone it composes an empty upstream list (test/core/compose-picker-config.test.js:148-160) and ai-gateway/src/proxy.js:52-54 throws before a listener ever binds - omitting the clause there is arguably correct. claude and claude-desktop both set requires_gateway *with* a gateway_upstream, so both really do bind a listener, and neither summary said so. claude-desktop is the sharper miss: this PR's own commit added a reassurance clause to that exact string while declining to add the listener clause it added two rows over on raw-anthropic/raw-openai. Both are now fixed, and the PR body's completeness note is corrected to name the real outliers and explain why hermes is different. - test/plugins/picker-disclosure.test.js only asserted the openclaw summary against a copy of 'openclaw gateway restart', so a rename of attach.js's RESTART_COMMAND would silently leave the manifest pointing at a command that no longer exists. RESTART_COMMAND is now exported from attach.js and the test asserts the summary contains it. Confirmed (not fixed here, pre-existing and unrelated): a hermes-only install throws 'ai-gateway: at least one upstream must be configured before start' at gateway source start, reproduced directly against proxy.js/source.js with the exact config compose-picker-config.test.js pins for hermes alone. Co-Authored-By: Claude <noreply@anthropic.com>
Neutral review round 1 -
|
Neutral review round 2 -
|
Three picker rows changed the machine without saying so in the one place the user reads before choosing. Each claim below was verified against the code before it was written.
raw-anthropic / raw-openai (
hypaware-core/plugins-workspace/ai-gateway/hypaware.plugin.json)For apps you manually point at HypAware.For apps you manually point at HypAware; starts a local gateway listener.Evidence: both rows set
compose.requires_gateway: true(ai-gateway/hypaware.plugin.json:31,40).composePickerConfigturns that into a@hypaware/ai-gatewayplugin instance (src/core/cli/walkthrough.js:774,798-804), whose source binds an HTTP server (ai-gateway/src/source.js:189->ai-gateway/src/proxy.js:49,58,82). Host/port is127.0.0.1:18521by default (ai-gateway/src/config.js:8). The port is deliberately not in the copy: the picker writes nolisten, so a taken port silently falls back to an ephemeral one (config.js:12,walkthrough.js:795-797, LLP 0114), and naming18521would have been a claim that is not always true.127.0.0.1is always true, hence "local".This is the same class of side effect the
otelrow already names ("starts a local receiver"), and these two rows compose no adapter that could disclose it anywhere else.openclaw (
hypaware-core/plugins-workspace/openclaw/hypaware.plugin.json)Live traffic plus local session history; attach rewrites OpenClaw's gateway config.Live traffic plus local session history; attach rewrites OpenClaw's gateway config, then you run 'openclaw gateway restart'.Evidence:
openclaw/src/attach.js:54definesRESTART_COMMAND = 'openclaw gateway restart'and:62-63the instruction attach prints, documented as required because a running OpenClaw gateway keeps routing at the oldbaseUrluntil restarted (verified 2026.3.13, LLP 0167#verify-results item 4). attach prints it only after the config has been rewritten, so the picker row is the only place the user can learn it before choosing.The manifest string and
RESTART_COMMANDwere only linked by eyeball;test/plugins/picker-disclosure.test.jsnow importsRESTART_COMMANDfromattach.js(now exported) and asserts the summary contains it, so a future rename of the command fails this test instead of silently leaving the manifest pointing at a command that no longer exists.claude-desktop (
hypaware-core/plugins-workspace/claude-desktop/hypaware.plugin.json)Requires Claude sign-in and admin approval.Requires Claude sign-in and admin approval; starts a local gateway listener; setup asks before changing anything.Evidence: the row is
needs_setup: truewithconfigure_command: "claude-desktop install"(claude-desktop/hypaware.plugin.json:29-30), the wizard runs that command through the configure phase (src/core/cli/wizard/configure.js:81), andrunInstallgates every applying step behind an explanation and a confirm that defaults to no before it touches the credential, helper, residue, or plist (claude-desktop/src/install.js:145-158,@ref LLP 0139#informed-consent). The reassurance is load-bearing next to "admin approval", which reads as a sudo ambush without it.The listener clause is separate from the setup step: the row's
composealso setsrequires_gateway: truewith a boundgateway_upstream(claude-desktop/hypaware.plugin.json:32-38), composed into the daemon config as soon as the row is picked, independent of whetherclaude-desktop installhas run. It is ordered before the setup clause so it does not read as somethingsetupcauses.claude (
hypaware-core/plugins-workspace/claude/hypaware.plugin.json)CLI and SDK conversations, including OpenClaw's claude-cli backend; attaches Claude Code and installs helper skills.CLI and SDK conversations, including OpenClaw's claude-cli backend; attaches Claude Code, starts a local gateway listener, and installs helper skills.Evidence: same as claude-desktop above, this row's
composesetsrequires_gateway: truewith a boundgateway_upstream(claude/hypaware.plugin.json:43-44), so picking it alone binds a real listener. This row was added to the PR after an earlier draft of this description incorrectly namedhermesas the row this issue left out of scope; see below for why that was wrong andclaude/claude-desktopare the actual outliers.Why
hermes, notclaude/claude-desktop, is genuinely out of scopeAn earlier version of this PR (and its description) said
hermeswas the remaining row that setsrequires_gatewaywithout naming a listener, and left it alone as a scoping note. That was backwards.hermes/hypaware.plugin.json:27-29setsrequires_gateway: truewith nogateway_upstream. Picked alone,composePickerConfigproduces a@hypaware/ai-gatewayplugin instance withupstreams: [](pinned attest/core/compose-picker-config.test.js:148-160, comment there notescompileUpstreamsaccepts the empty list at config-compile time). Butai-gateway/src/proxy.js:52-54throws'ai-gateway: at least one upstream must be configured before start'when the compiled upstream list used to start the listener is empty, and hermes registers no upstream preset of its own (hermes/src/index.jshas noregisterUpstreamPresetcall). So a hermes-only install does not compose a working listener at all; today it throws at gateway source start. Omitting a listener clause from hermes's summary is therefore arguably correct, not an oversight, and is left alone here.claudeandclaude-desktop, by contrast, both setrequires_gatewaywith agateway_upstream, so both really do produce a bound listener when picked, and neither summary said so.claude-desktopwas the sharper miss: this PR's original commit edited that exact summary string to add the "asks before changing anything" reassurance while declining to add the listener clause it added two rows over onraw-anthropic/raw-openai. Both are now fixed above.Separately: the
hermes-alone throw looks like a pre-existing bug (a picker row that composes arequires_gatewayconfig with no way to reach a working upstream). It reproduces by code inspection and by direct invocation ofstartProxy/mergeUpstreamswith the exact configcompose-picker-config.test.jspins for hermes-alone. It predates this PR, is unrelated to picker copy, and is not fixed here; filing separately.Tests
Extended
test/plugins/picker-disclosure.test.jswith six pins (openclaw restart command sourced fromattach.js'sRESTART_COMMANDrather than a copied literal, raw-anthropic listener, raw-openai listener, claude-desktop reassurance, claude listener, claude-desktop listener), each asserting the substance rather than exact wording so the copy stays re-tunable but the admission cannot vanish again. Each pin carries a comment citing the code it is derived from. Reverting each new manifest clause locally was confirmed to fail its corresponding test before restoring it.Checked and unchanged because they do not assert this copy:
test/plugins/openclaw-manifest.test.js(matches/live/i,/session history/i,/claude-cli/),test/core/config.test.js(synthetic manifest fixtures),test/core/walkthrough-prompt.test.js(unanchored prefix match on the Anthropic row, still true after the suffix). No assertion was loosened.node scripts/run-tests.js: 3580 pass, 0 fail, 1 skipped.npx tsc -p tsconfig.json --noEmit: clean.No LLP text touched. LLP 0139 is
Acceptedand records the consent gate this copy now surfaces; it needed no change.Fixes #637
🤖 Generated with Claude Code