You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Severity: Medium-high observability and usability defect
Category: Click actions / runtime diagnostics / user trust
Related work:#47 addresses stale click commands across reload; #53 bounds diagnostic presentation; #21 covers optional user notifications. This issue makes the existing click-command runner observable without changing those scopes.
Problem and intended outcome
Pinchos lets each item run an arbitrary command on normal left-click, but the result of that command is effectively invisible.
ManagedItem.processClick starts clickRunner.runIfIdle() and discards the returned outcome. The runner internally retains whether it is active, its last execution, and skipped invocations, but ManagedItem.runtimeSnapshot() exposes only the primary refresh runner. StatusItemController.makeLifecycleMenu also retrieves declarative action snapshots, not the click runner snapshot.
As a result, users cannot tell whether a click command:
started or was skipped because another click command was still active;
completed successfully;
failed to launch because its shell or working directory became unavailable;
exited non-zero or by signal;
timed out or was cancelled by reload/removal/shutdown;
wrote a useful error to stderr;
had stdout/stderr truncated;
is still running.
This is a serious gap for a command-driven tool whose central promise is that users may choose freely what gets displayed and what actions those items perform. A click that appears to do nothing is indistinguishable from a command failure, a busy-runner skip, or successful background work.
The intended outcome is compact native diagnostics for the configured click command, using the same command-session vocabulary as refresh and declarative action runners while keeping the primary displayed value independent.
Current evidence
Relevant implementation in Sources/pinchos/ManagedItem.swift:
clickRunner is created from the item's click command and execution settings.
processClick(eventType:) awaits clickRunner.runIfIdle() but does not retain or project the returned outcome beyond what the private runner already stores.
runtimeSnapshot() combines the primary runner with item presentation state only.
actionSnapshot(at:) exists for declarative actions, but there is no corresponding click snapshot API.
click invocation bookkeeping is used for safe update/removal settlement, not user-visible status.
Relevant implementation in Sources/pinchos/StatusItemController.swift:
lifecycle menus show primary runtime state and main-runner diagnostics;
command actions receive separate diagnostics sections through their snapshots;
no section or menu action exposes the click runner.
The README describes click as fire-and-forget. Fire-and-forget should mean the left-click does not block the UI or replace the item's main value; it should not mean failures and skips are permanently undiscoverable.
Required behavior
When an item has a configured click command, its right-click menu should include a compact Click Action diagnostics section.
At minimum, expose:
current state: never run, running, completed, error, timed out, or cancelled;
last attempted/completed time;
last duration;
final exit code, signal, timeout, cancellation, or launch-failure reason;
The click runner must remain independent from the primary item status:
a click failure must not replace the menu-bar value or overwrite the primary runner's last-good output;
a successful click must not become the item's displayed refresh value;
the item may show a subtle action diagnostic marker only if a separate explicit UX decision is approved; the baseline is discoverability through the right-click menu.
Diagnostics should be retained for the currently configured click runner. Define clear reset semantics:
unchanged click command/execution settings retain diagnostics across presentation-only reloads;
changing or removing click execution settings cancels the old generation and removes or archives its diagnostics according to one documented rule;
removal/shutdown may discard diagnostics only after lifecycle settlement;
A presentation-only config reload retains the click runner and its diagnostics.
Changing the click command, shell, environment, working directory, timeout, or output limit follows the documented reset/generation policy and cannot expose obsolete diagnostics as current.
Removing click removes its diagnostics after the old runner is safely quiesced.
Click failure does not alter lastSuccessfulOutput, lastUpdatedAt, primary error state, staleness, title, or tooltip output.
Menu construction remains bounded and responsive at the maximum allowed retained output.
VoiceOver/accessibility labels distinguish primary-runner, click-action, and declarative-action diagnostics.
swift test and swift build -c release pass.
Likely implementation areas
Sources/pinchos/ManagedItem.swift
expose clickSnapshot() or a unified named-runner snapshot collection
preserve generation/reset semantics
Sources/pinchos/StatusItemController.swift
add the bounded click diagnostics section and copy actions
A unified diagnostics model for primary, click, and named action runners may reduce duplication, but it must preserve the semantic distinction that only the primary runner drives the displayed value.
Verification plan
Add headless managed-item tests for every terminal reason, active state, skip count, output bounds, and reload reset/retention rule.
Add menu tests that assert section ordering, concise titles, copy payloads, and global action placement.
Launch a release GUI and exercise success, failure, timeout, repeated click, reload, removal, and recovery paths.
Perform VoiceOver/accessibility inspection in a permitted GUI session.
Run the full suite and release build.
Risks and dependencies
Diagnostics must not turn a lightweight fire-and-forget action into a second displayed status channel. Keep state retention bounded, render it only when the menu is opened, and reuse existing runner snapshots.
This issue should consume the definitive session result from #48; otherwise click diagnostics could repeat the same preliminary-shell versus final-descendant inconsistency.
Severity and category
Severity: Medium-high observability and usability defect
Category: Click actions / runtime diagnostics / user trust
Related work: #47 addresses stale click commands across reload; #53 bounds diagnostic presentation; #21 covers optional user notifications. This issue makes the existing click-command runner observable without changing those scopes.
Problem and intended outcome
Pinchos lets each item run an arbitrary command on normal left-click, but the result of that command is effectively invisible.
ManagedItem.processClickstartsclickRunner.runIfIdle()and discards the returned outcome. The runner internally retains whether it is active, its last execution, and skipped invocations, butManagedItem.runtimeSnapshot()exposes only the primary refresh runner.StatusItemController.makeLifecycleMenualso retrieves declarative action snapshots, not the click runner snapshot.As a result, users cannot tell whether a click command:
This is a serious gap for a command-driven tool whose central promise is that users may choose freely what gets displayed and what actions those items perform. A click that appears to do nothing is indistinguishable from a command failure, a busy-runner skip, or successful background work.
The intended outcome is compact native diagnostics for the configured click command, using the same command-session vocabulary as refresh and declarative action runners while keeping the primary displayed value independent.
Current evidence
Relevant implementation in
Sources/pinchos/ManagedItem.swift:clickRunneris created from the item's click command and execution settings.processClick(eventType:)awaitsclickRunner.runIfIdle()but does not retain or project the returned outcome beyond what the private runner already stores.runtimeSnapshot()combines the primary runner with item presentation state only.actionSnapshot(at:)exists for declarative actions, but there is no corresponding click snapshot API.Relevant implementation in
Sources/pinchos/StatusItemController.swift:The README describes
clickas fire-and-forget. Fire-and-forget should mean the left-click does not block the UI or replace the item's main value; it should not mean failures and skips are permanently undiscoverable.Required behavior
When an item has a configured
clickcommand, its right-click menu should include a compact Click Action diagnostics section.At minimum, expose:
The click runner must remain independent from the primary item status:
Diagnostics should be retained for the currently configured click runner. Define clear reset semantics:
Bounded scope and non-goals
In scope:
Explicit non-goals:
NSMenuItemtitle.clickinto an action table.Testable acceptance criteria
clickcommand shows no click diagnostics section.Never runstate.clickremoves its diagnostics after the old runner is safely quiesced.lastSuccessfulOutput,lastUpdatedAt, primary error state, staleness, title, or tooltip output.swift testandswift build -c releasepass.Likely implementation areas
Sources/pinchos/ManagedItem.swiftclickSnapshot()or a unified named-runner snapshot collectionSources/pinchos/StatusItemController.swiftSources/PinchosCore/CommandExecution.swiftCommandRunnerSnapshotand definitive session result from [bug] Finalize command sessions only after descendants and output pipes settle #48Tests/pinchosTests/RecoveryLifecycleTests.swiftTests/pinchosTests/StatusItemControllerTests.swiftTests/PinchosCoreTests/CommandRunnerTests.swiftdocs/manual-qanative-menu/accessibility evidenceA unified diagnostics model for primary, click, and named action runners may reduce duplication, but it must preserve the semantic distinction that only the primary runner drives the displayed value.
Verification plan
Risks and dependencies
Diagnostics must not turn a lightweight fire-and-forget action into a second displayed status channel. Keep state retention bounded, render it only when the menu is opened, and reuse existing runner snapshots.
This issue should consume the definitive session result from #48; otherwise click diagnostics could repeat the same preliminary-shell versus final-descendant inconsistency.