Repository navigation
deps: skillinject v0.2.4, dataexchange v0.2.3, updater v0.2.5 (+ pilotctl update status) - #468
Merged
Merged
Conversation
…tctl update status) Bump the three wave-2 libraries (common v0.5.14 and the sigstore-go / go-openapi versions updater v0.2.5 requires come along via MVS) and do the web4 follow-ups their PRs call for. updater#49: - `pilotctl update` passes StatusPath ~/.pilot/update-state.json, the file the pilot-updater loop already writes, so manual runs are recorded. - RunOnce's error is checked: a failed check exits 1 with code update_failed instead of printing success. A successful run reports updated vs up to date and warns when restart_error is set; --json adds result, updated, current/latest version, restart_error, status_file. - `pilotctl update status` reads the record: last check, result, error, failure streak, versions, last update and "Daemon restart: NEEDED" with restart_error. --json adds last_result, last_error, restart_error, status_file and the full update_state. skillinject#39: - `skills check|enable` and the `update` skills summary count ActionRemove and print Outcome.Note (text + --json removes/notes). - `skills disable all` counts RemovalNeutralized and prints Removal.Note. - `skills status --json` includes note; --verbose prints it. dataexchange#43 needs no web4 change: the inbox byte-cap fix and dedupe are receiver-side and pilotctl sends untagged frames. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…aries Review follow-ups on #468. F1/F2 - stale restart_error. updater v0.2.5 keeps an earlier restart_error after a manual run that restarted the daemon (every release replaces pilot-updater, and recordCheck clears it only when it did not), and it clears it on a later check only on Linux. LastStatus merges the record on disk, so `pilotctl update` warned "the daemon is not running them" right after a successful restart, and every later run on macOS warned again with `update status` stuck at NEEDED. pilotctl now asks the daemon over IPC which version it runs (info "version", bounded to 3s) before it reports anything: - daemon on the installed version: the record is out of date; no warning, `update status` says "not needed". - daemon on another version: warn, and name a restart command when the updater's message has none (its macOS message only names the launchctl call that failed). - no daemon: an update run warns that the daemon is not running and how to start it; an up-to-date run says nothing; `update status` says "daemon not running". When an update run leaves restart_error unchanged from before the run, pilotctl waits up to 30s for a just-restarted daemon to answer. A restart_error this run recorded is checked once. --json adds restart_needed, daemon_running and daemon_version; restart_error is "" when the daemon runs the installed version (update_state keeps the record as written). F3 - the fake updater now merges into the on-disk record the way updater v0.2.5's recordCheck does, and the new tests cover an update after a failed restart, an up-to-date run on a record holding a restart_error, and both with no daemon. The tests assert that the merged record still carries the old restart_error, so they exercise the stale path. F4 - main() takes --verbose/-v as the global flag before dispatch, so `skills status --verbose` never saw it. skills status now honours the global flag too. F5 - the reconcile summary said "Removed:" for every retired row. Each row now says what happened to the file: helpers and plugin files deleted, the pilot block stripped from a heartbeat file (file kept), the plugin entry removed from openclaw.json (file kept). Disabled-mode passes, which only prune retired surfaces, now say injection is disabled, and --json adds disabled. The update skills line says so too. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
| }() | ||
| select { | ||
| case res := <-ch: | ||
| d.Close() |
| v, _ := res.info["version"].(string) | ||
| return v, true | ||
| case <-time.After(daemonProbeTimeout): | ||
| d.Close() // unblocks the Info call |
TeoSlayer
enabled auto-merge (squash)
September 24, 2026 01:22
# Conflicts: # CHANGELOG.md # go.mod # go.sum
TeoSlayer
pushed a commit
that referenced
this pull request
Sep 24, 2026
…ctl update status) into feat/native-https-proxy Conflicts: - cmd/pilotctl/updates.go: #468's result fields and printUpdateResult, plus the branch's fitTransportToDaemon note for update --pin (JSON "note", text "Note:"), with a test that the two coexist. - CHANGELOG.md: both Fixed lists kept. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bumps the three wave-2 libraries and makes the web4 changes their PRs ask for: skillinject#39, dataexchange#43 and updater#49.
02fd110 fixes the review findings. It checks the recorded
restart_erroragainst the version the daemon reports (F1, F2). The fake updater merges the on-disk record the way the real one does (F3).skills status --verboseworks again (F4). The skills summary says what each retired-surface removal did to the file and whether injection is disabled (F5).Dependency bumps
github.com/pilot-protocol/skillinjectgithub.com/pilot-protocol/dataexchangegithub.com/pilot-protocol/updatergithub.com/pilot-protocol/commonThe other go.mod changes are indirect: sigstore-go v1.3.0, timestamp-authority v2.1.3, go-logr v1.4.4 and the go-openapi set. updater v0.2.5 requires them in its own go.mod, so MVS pulls them in and they cannot be left out. No other direct dependency changed.
gostays 1.25.13 and grpc stays v1.83.2.updater#49 follow-up (
cmd/pilotctl/updates.go)Problem:
pilotctl updatecalledu.RunOnce()and then always printed success.pilotctl --json updateprinted{"status":"ok"}and exited 0 even on a GitHub 403. Manual runs were not recorded anywhere.update statusshowed only the auto-update flag and pilotctl's version.Changes:
pilotctl updatepassesStatusPath: ~/.pilot/update-state.json, usingconfigDir(), soPILOT_HOMEis honored. The pilot-updater loop already writes this file, because the library defaults it to the directory of--state-path. Manual and automatic checks now share one record.cmd/updaterneeds no change.fatalHint("update_failed", …). The message isupdate failed: <updater error>and the hint points topilotctl update status. With--json, stdout is empty and stderr gets the usual error envelope.Updated to vX.orAlready up to date (vX).. The exit code stays 0 because the install succeeded.restart_erroris checked against the daemon before pilotctl reports it. The record alone can be out of date. updater v0.2.5 keeps an earlierrestart_errorafter a manual run that restarted the daemon: every release replaces pilot-updater, andrecordCheckclears the field only when it did not. It also clears it on a later check only on Linux, from/proc. So when arestart_erroris recorded, pilotctl asks the daemon over IPC which version it runs (info.version, bounded to 3 s):pilotctl daemon stop && pilotctl daemon start) when that message has none; the macOS message only names thelaunchctl kickstartthat failed.restart_errorunchanged from before the run, pilotctl waits up to 30 s for a just-restarted daemon to answer (pilotctl daemon startwaits 30 s too). Arestart_errorthis run recorded is checked once, without waiting.--jsonaddsresult,updated,current_version,latest_version,restart_error,restart_needed,daemon_running,daemon_versionandstatus_file.restart_erroris""when the daemon runs the installed version.pilotctl update statusreads the record withupdater.ReadStatus:restart_errorrecorded it shows one of three lines.Daemon restart: NEEDED — the daemon runs vA, installed is vBmeans the daemon runs another version.daemon not running — vB runs when it startscomes with the start command.not needed — the daemon runs the installed vBmeans the record is out of date.--json: addsstatus_file,last_result,last_error,restart_error,restart_needed,daemon_running,daemon_versionand the full record asupdate_state.update_statekeeps the record as written and isnullwhen no check has been recorded. A file that cannot be read or parsed is reported asstatus_errorand does not fail the command.newUpdateRunneranddaemonVersionProbeare package vars so tests can use a fake updater and a fake daemon. Production behavior is unchanged.restart_errorafter a manual run whose restart succeeded, and after a check that finds the daemon on the installed version on macOS. That needs an updater release, so it is not in this PR. The daemon check here stays correct either way.updatehelp text and thecontext"returns" string describe the new output. The top-level--helpdid not change. I ranscripts/gen-cli-reference.shanddocs/cli-reference.mdcame out byte-identical, so it is not in the diff.Not done here (updater#49 lists it under "Later"): using
loop_pidandnext_check_atto warn that no updater loop is running.skillinject#39 follow-up (
cmd/pilotctl/skills.go)Problem: skillinject v0.2.4 reports retired surfaces as
state=retired, action=removeand addsOutcome.Note,Removal.NoteandRemovalNeutralized. Before this PR, the summaries dropped all of them.Changes:
skills checkandskills enablenow share one summary:remove: N (retired surfaces from an older manifest)and aRetired surfaces cleaned up:list. Both print only when N > 0. Each row says what happened to the file: helpers and plugin files aredeleted. From a heartbeat file only the pilot block is stripped, and fromopenclaw.jsononly the plugin entry is removed; both lines sayfile kept.Skill injection is disabled: nothing was installed or updated.andReconcile complete — retired surfaces only, N found., and--jsonaddsdisabled.Notes:block for any row that has a note. That is a heartbeat file shared with another tool, or a retired plugin that was neutralized instead of removed.--jsonaddsremovesandnotes(always an array).enable --jsonnow also includesnoops.pilotctl updateskills line is now(… up-to-date, … installed, N removed, … errors)and is followed by any notes. In disabled mode it readsSkills: injection disabled — retired surfaces cleaned up: N, errors: M.skills disable allcountsneutralizedand printsnote:under each processed path. The count column is 2 characters wider to fitneutralized:.skills status:--jsonincludes each row'snoteand--verboseprints it.main()takes--verboseand-vas the global flag before dispatch, soskills status --verbosenever saw the flag; only--verbose=trueworked, and that bug is on main too.skills statusnow also honors the global flag.dataexchange#43
No web4 change needed:
cmd/daemonbuildsServiceConfigwith the defaults, which now evict the oldest files instead of the whole inbox.MessageIDorReplyTo, so its frames stay untagged and are byte-for-byte unchanged on the wire.--waitreplies by request ID is the separate batch-3b PR (see dataexchange#43's deploy notes).Tests
All run with
GOWORK=offon 02fd110 (the review fixes). 1af6e22 passed the same set.go build ./...ok.GOOS=linux go build ./...ok.go vet ./cmd/... ./pkg/daemon/is clean, andgofmt -lis clean.go test ./cmd/... ./pkg/daemon/... -count=1: all ok. That covers cmd/daemon, cmd/pilotctl, cmd/updater, pkg/daemon and its subpackages.go test ./tests/ -run TestDataExchange -count=1: ok. This is the integration check against dataexchange v0.2.3.cmd/pilotctl/zz_update_state_test.go(uses a fake updater and a fake daemon probe; no network, no real daemon):update-state.jsonalready on disk, the way updater v0.2.5'srecordCheckdoes. That includes leaving an earlierrestart_errorin place.update_failedin text and JSON, with empty stdout in JSON.restart_error: ""andrestart_needed: false. If the daemon never reports the new version,restart_neededis true.restart_error, with the daemon already restarted: no warning, andupdate statussaysnot needed. With the daemon stopped,update statussaysdaemon not runningand gives the start command.restart_errorthis run recorded is probed once, without waiting.printUpdateResultcovers three install cases: the daemon on the old version (with the restart hint for the macOS message, and no second command for a Linux one), the daemon on the new version, and no daemon. It covers three up-to-date cases: no restart error, no daemon, and the daemon on the old version.update statusfor no record, a failing record with a restart error, a healthy pinned record, and an unreadable file.pilotctl updateis then shown byupdate status.cmd/pilotctl/zz_skills_summary_test.go:notes: []when empty.disabled, and the disabledupdateline.updatesummary line.disable allwith a neutralized row.skills statusdetail follows the global--verbose/-vthatmain()consumes (driven throughmain()), and--verbose=true.RunOnceerror ignored again andStatusPathunset, 3 of the new update tests fail.restart_error(the 1af6e22 behavior) fails 5 update tests.launchctlrestarts a fake IPC daemon that reports the version in.pilot-version. Nothing touched~/.pilotor the running daemon.NEEDEDon the next up-to-date run.(it runs v1.13.8, installed is v1.13.9)with the restart command.--jsonshowsrestart_error: ""anddaemon_version: v1.13.9. The run took 8 s including the download.update statussaysnot needed.update statussaysdaemon not running … start it with: pilotctl daemon start. An update run with the daemon stopped warns that it is not running.skillswith the real binary and live manifest, in a scratch HOME set up like the review repro:skills status --verboseprints per-file rows and the shared-heartbeatnote.skills checklistsHEARTBEAT.md — openclaw: pilot block stripped, file keptandopenclaw.json — pilotprotocol-prompt-injector: plugin entry removed, file kept. Both files still exist with user text and other keys intact.skills disable all,skills checksays injection is disabled, and--jsonhasdisabled: true.The worktree's pre-commit
go vethook picks up the parentgo.workunless it runs withGOWORK=off. It passed once run that way. This is a local setup issue, not something this PR changes.Deploy notes
r=, and the retired-surface prune on their next start or tick. Disabled hosts are cleaned on the nextpilotctl skills checkor the post-update tick ofpilotctl update.Restart=alwaysare now restarted onto new binaries. In every other caserestart_erroris set, andpilotctl updateandupdate statusreport it after asking the daemon which version it runs.restart_errorafter a manual run whose restart succeeded when pilot-updater was replaced (status.gorecordCheck), and have an up-to-date check on macOS clear it when the daemon runs the installed version.🤖 Generated with Claude Code