@@ -77,11 +77,24 @@ type attachLaunch struct {
7777
7878// nativeResumeHint composes the daemon-exit resume guidance from the tool's
7979// grounded ResumeSpec (session-attach design §2.4). When native resume is not
80- // yet grounded it degrades to a generic, honest phrase rather than asserting a
81- // resume command the tool may not support. Dispatch is on the ResumeSpec shape,
82- // never a tool-name branch (CLAUDE.md #3).
80+ // yet grounded — the ResumeNone case that now covers 17 of the 19 attachable
81+ // launchers (attach-all-launchers) — it degrades HONESTLY: for a launchable
82+ // tool it points at the manual `observer <verb> --continue-from <id>` handover
83+ // fork (the real mortality backstop for a daemon-restart-ends-the-session
84+ // tool), and only falls back to the fully-generic phrase when even the launch
85+ // verb is unknown. Dispatch is on the capability SHAPE (ResumeSpec kind +
86+ // Handoff.Launch presence), never a tool-name branch (CLAUDE.md #3). This is
87+ // the ONE seam where the "daemon restart = session over" reality lands for a
88+ // ResumeNone tool — reportAttachResult's daemon-exit / conn-lost / input-stall
89+ // branches interpolate it.
8390func nativeResumeHint (capab integration.Capability ) string {
8491 if capab .Resume .Kind != integration .ResumeNative || capab .Resume .Subcommand == "" {
92+ if capab .Handoff .Launch != nil && capab .Handoff .Launch .Subcommand != "" {
93+ return fmt .Sprintf (
94+ "start a new session (`observer %s --continue-from <session-id>` carries a distilled handover)" ,
95+ capab .Handoff .Launch .Subcommand ,
96+ )
97+ }
8598 return "resume it natively to continue"
8699 }
87100 switch capab .Resume .IDMechanism {
@@ -103,20 +116,25 @@ func nativeResumeHint(capab integration.Capability) string {
103116//
104117// - --no-proxy-route when the escape hatch is engaged (the inner launcher
105118// then skips base-URL / `-c openai_base_url` injection);
106- // - --proxy <url> when the operator overrode the proxy URL;
119+ // - <proxyFlag> <url> when the operator overrode the proxy URL — the flag
120+ // NAME is the inner launcher's own proxy-override spelling (`--proxy` for
121+ // most, `--proxy-url` for hermes/pi), passed in so shared code never
122+ // branches on tool identity (CLAUDE.md #3); emitted only when BOTH
123+ // proxyFlag and proxyOverride are non-empty (a seed-only launcher with no
124+ // proxy flag passes proxyFlag="" and the override is dropped);
107125// - --config <path> when the outer invocation used a non-default config;
108126// - passthrough... launcher-specific wrapper flags the inner launcher
109127// should honor (e.g. --claude-path/--codex-path, --no-app-server-check),
110128// enumerated explicitly by each launcher (B2-6);
111129// - -- <toolArgs...> the operator's trailing tool args (`observer codex
112130// --attach -- --model X`), so launcher state is not dropped.
113- func attachExtraArgs (noProxyRoute bool , proxyOverride , configPath string , passthrough , toolArgs []string ) []string {
131+ func attachExtraArgs (noProxyRoute bool , proxyOverride , proxyFlag , configPath string , passthrough , toolArgs []string ) []string {
114132 var args []string
115133 if noProxyRoute {
116134 args = append (args , "--no-proxy-route" )
117135 }
118- if proxyOverride != "" {
119- args = append (args , "--proxy" , proxyOverride )
136+ if proxyOverride != "" && proxyFlag != "" {
137+ args = append (args , proxyFlag , proxyOverride )
120138 }
121139 if configPath != "" {
122140 args = append (args , "--config" , configPath )
0 commit comments