Commit graph

80 commits

Author SHA1 Message Date
843e3d01f0 feat(proc): direct drop-in port from 4x raw Process to Proc singleton (exact poll-act-poll behavior preserved)
- Removed import Quickshell.Io + all 4 Process { toggleProcess, copyProcess, exitNodeProcess, statusCheck }
- All one-shot commands now use Proc.runCommand(id, argv, (stdout, exitCode) => {...})
- _pendingAction moved to clean root property (was hacked onto statusCheck object)
- Introduced _runStatusCheck() helper + updated wrappers (toggleTailscale, refreshStatus, setExitNode, copyToClipboard, _runNextCopy)
- Exact same sequencing and defensive logic:
  * toggle: set pending → status poll for truth → decide up/down → act → post-act status verify
  * copy retry state machine unchanged (just Proc instead of .command/.running)
  * exit-node and generic refresh paths identical
- Added explicit comment documenting why the poll-act-poll exists (defensive, not forbidden state per AGENTS.md)
- stderr detail dropped from action errors (per chosen A strategy; generic messages only)
- All new JS follows repo ; + {} style
- I18n wrappers already in place from prior slice

Written by AI agent working for @jtmorris. Model: grok-build-0.1.
2026-05-25 03:00:33 +00:00
cb280d1e4e feat(i18n): wrap all user-facing strings in TailscaleWidget.qml with I18n.tr (strategy A)
- header, details, exit node prefix/none, invalid hostname, copied (with .arg), all formatError toasts
- Glyph literals ("×", "↗", "—") left as-is (decorative, not linguistic)
- "tailscalectl" toast titles kept as technical IDs
- All call sites now go through I18n for future translation
- Tests unaffected (still green)

Written by AI agent working for @jtmorris. Model: grok-build-0.1.
2026-05-25 03:00:33 +00:00
7942bc3471 feat(i18n): make lib.js strings I18n source keys (strategy A); remove dead symbol exports; update tests; add i18n/ scaffolding + en.json placeholder
- getStrings().copied now returns template key "Copied %1 to clipboard" (interpolation at QML call site via .arg)
- Removed unused clearExitNode/setExitNode from getStrings (were dead code)
- Tests updated for new shape while preserving coverage
- New tailscalectl/i18n/ with README + en.json for future-proofing (per dms-plugin-dev best practice)
- Exact behavior preserved; no logic changes

Written by AI agent working for @jtmorris. Model: grok-build-0.1.
2026-05-25 03:00:33 +00:00
aacc027984 style: strictly enforce semicolon termination + curly braces on all JS statements
- lib.js, test/lib.test.js, and all executable JS in TailscaleWidget.qml (onExited handlers, custom methods, onClicked blocks) now terminate every statement with ;
- All if/for/while blocks use {} even for single statements (per repo code style rules)
- No behavior change; all tests continue to pass
- This was the missing follow-up to the previous refactor (the changes existed in the working tree but were never committed on the feature branch)

Written by AI agent working for @jtmorris. Model: grok-build-0.1.
2026-05-25 03:00:33 +00:00
7b41d7177f refactor: extract toggle decision logic to lib.js and scope one-shot coordination to statusCheck Process
- Add PendingAction constant and commandForPendingAction pure function (fully tested)
- Remove root _pendingToggle property
- Use dynamic _pendingAction on the statusCheck Process for the fresh-status hand-off
- Introduce refreshStatus() helper and deduplicate the two post-action refresh sites
- All JS statements now terminate with semicolons; all blocks use braces
- Behavior unchanged; coordination token no longer leaks to widget root
- Enables future post-status actions without adding more root properties

Written by AI agent working for @jtmorris. Model: grok-build-0.1.
2026-05-25 03:00:33 +00:00
12ef07040c Code formatting cleanup. 2026-05-25 03:00:33 +00:00
b02f8ba45b test: update coverage comment to reflect current reality
- Remove all historical references (#48, first-principles, newly extracted, etc.)
- Remove mentions of deleted components (5s Timer, old copy state machine)
- Make the comment strictly about what the tests actually cover and the real shortcoming (no automated QML coverage)
- Per request: code comments exist to explain the code, not preserve history
2026-05-25 03:00:33 +00:00
6e4e5d51ec refactor(clipboard): replace object map + 4 helpers with simple array + getClipboardCommands; QML becomes dumb index driver
- lib.js: single clipboardTools array + getClipboardCommands(text) returning argv lists
- Delete validateClipboardTool, buildCopyCommand, nextClipboardTool, allClipboardTools, safeClipboardTools, old clipboardTools object
- Remove noClipboardTool / invalidClipboardCommand from getStrings (dead)
- TailscaleWidget.qml: remove _copyCurrentTool + _executeCopy; add _copyIndex + _runNextCopy
- copyProcess.onExited and copyToClipboard now purely index-driven, no tool names
- Update tests: remove 4 old clipboard test blocks + dead string assertions; add focused getClipboardCommands tests
- All 34 tests pass

This is the minimal honest design given Process is a QML type.
2026-05-25 03:00:33 +00:00
e695db6650 security: validate hostname in makeExitNodeCommand (balanced paranoia, direct-argv defense-in-depth, TDD) 2026-05-25 03:00:33 +00:00
a40d8d49a4 refactor: centralize remaining error paths and popout strings via formatError + getStrings (final polish pass) 2026-05-25 03:00:33 +00:00
4a7803dc42 refactor: simplify copy path — drop caching and multi-tool retry state machine, keep simple dms→wl-copy fallback (first-principles plan) 2026-05-25 03:00:33 +00:00
5ace4095c6 feat: remove 5-second refreshTimer — first major step toward low-duty-cycle architecture (on-demand + post-action verification only) 2026-05-25 03:00:33 +00:00
619c988f56 chore: remove historical issue-chasing comments from QML and lib.js (per first-principles plan) 2026-05-25 03:00:33 +00:00
9dd73b6d55 refactor: add getStatusCommand pure helper + test (TDD step 2 — prepares low-duty-cycle status calls) 2026-05-25 03:00:33 +00:00
6b71197770 refactor: introduce formatError centralizer + remove first batch of historical comments (TDD step 1 of first-principles plan) 2026-05-25 03:00:33 +00:00
ee36ae5c72 chore: evaluate structured logging per AGENTS.md rule 1 — no addition justified (#47)
- Existing toasts + truncated stderr provide the actionable information for users and errors
- Adding persistent debug logs would introduce state, rotation, and maintenance concerns
- with no demonstrable improvement to UX, decisions, or security for normal operation
- Explicit no-op commit closes the planning issue

Written by AI agent working for @jtmorris. Model: Grok build-0.1.
2026-05-25 03:00:33 +00:00
e1569dd870 fix: eliminate toggle decision staleness via poll-then-act (no cached desired state) (#42)
- toggleTailscale() now forces a fresh statusCheck instead of reading possibly-stale root.isConnected
- The actual up/down decision happens in statusCheck.onExited using the just-received value
- _pendingToggle is a transient one-shot flag (reset immediately after use) — not a persistent 'desired state' cache
- Complies with AGENTS.md rule 1 / #11

Written by AI agent working for @jtmorris. Model: Grok build-0.1.
2026-05-25 03:00:33 +00:00
b10503f4d5 test: coverage for newly extracted pure helpers; document Process/Widget manual verification boundary (#48)
- The new helpers from #43 are now under test
- Added explicit comment explaining that full lifecycle + timing + QML behavior remains manual verification only (no QML test runner exists)

Written by AI agent working for @jtmorris. Model: Grok build-0.1.
2026-05-25 03:00:33 +00:00
440e954099 refactor: extract shouldShowClearExitNode and isActiveExitNode to lib.js (TDD) — light progress on #43
- Two small pure UI predicates moved out of QML delegate
- QML now calls TailscaleLib.* (thinner glue)
- New tests + all existing tests pass
- No new state, no architecture change

Written by AI agent working for @jtmorris. Model: Grok build-0.1.
2026-05-25 03:00:33 +00:00
925233dfb9 feat: extract UI strings to lib.js; harden clipboard to direct argv, drop clipmanctl (#34, #49)
- safeClipboardTools now only dms + wl-copy (clipmanctl removed as niche optional history manager)
- buildCopyCommand now returns pure argv arrays (no sh -c, no escaping, eliminates future injection risk)
- Added getStrings() for centralised user-facing strings (prep for real i18n)
- Updated all tests (TDD) and README
- All 29 tests pass

Written by AI agent working for @jtmorris. Model: Grok build-0.1.
2026-05-25 03:00:33 +00:00
89d95cb864 chore: remaining issues batch progress (#23-#34) 2026-05-25 03:00:33 +00:00
62a364d14e chore: JS quality batch (#20 for-in guard, #21 add edge tests, #22 dedup errorMessage keys) 2026-05-25 03:00:33 +00:00
2a53748895 chore: batch minor layout fixes (#18, #19, #27) - Row anchors, boundsBehavior 2026-05-25 03:00:33 +00:00
8a31851769 chore: verify copyProcess already has proper onExited exit-status check + success toast
Toast moved out of copyToClipboard() into onExited (code===0 path).
Fallback clipboard rotation also present.
Issue #17 already addressed by existing implementation.
Fixes #17
2026-05-25 03:00:33 +00:00
cafc281949 chore: confirm single authoritative error path for statusCheck
parseStatusResult safely catches JSON errors (lib.js:68).
onStreamFinished performs no toasts.
All failure toasts centralized in statusCheck.onExited (TailscaleWidget.qml:103).
Eliminates historical double-toast spam described in #13.
Fixes #13
2026-05-25 03:00:33 +00:00
028be9d571 Better scoped semicolon coding style. 2026-05-25 03:00:33 +00:00
1cb01144a5 Added some opinionated coding style guidelines. 2026-05-25 03:00:33 +00:00
1a937a8249 fix: remove binaryAvailable, fix statusCheck parser location, add timer guard
- Revert binaryAvailable property: reintroduced stale-state anti-pattern
  already rejected in #11. All error paths already handled by Process
  onExited handlers.
- Move statusCheck parsing from onStreamFinished to onExited (#38):
  parser now only runs after exit code validation, preventing stale
  data from being applied on failure.
- Add refreshTimer guard (#44): timer no longer spawns new statusCheck
  while one is already running.

Closes #38, #44. Reverts #52 partial fix.
2026-05-25 03:00:33 +00:00
afdcba9d4c fix: remove propagateComposedEvents and fix plugin author (#50, #51)
- TailscaleWidget.qml: remove propagateComposedEvents from right-click MouseArea
- plugin.json: clean up author string
2026-05-25 03:00:33 +00:00
da4d566f0c fix: lib.js security and correctness fixes (#40, #41)
- parsePeers: add hasOwnProperty guard and filter null entries
- findActiveExitNode: add hasOwnProperty guard to for..in loop
- makeExitNodeCommand: handle empty hostname correctly
2026-05-25 03:00:33 +00:00
f08b01314e chore: remaining issues batch progress (#23-#34) 2026-05-25 03:00:33 +00:00
2a6b3aea6a chore: JS quality batch (#20 for-in guard, #21 add edge tests, #22 dedup errorMessage keys) 2026-05-25 03:00:33 +00:00
2bad002c69 chore: batch minor layout fixes (#18, #19, #27) - Row anchors, boundsBehavior 2026-05-25 03:00:33 +00:00
97ec919170 chore: verify copyProcess already has proper onExited exit-status check + success toast
Toast moved out of copyToClipboard() into onExited (code===0 path).
Fallback clipboard rotation also present.
Issue #17 already addressed by existing implementation.
Fixes #17
2026-05-25 03:00:33 +00:00
2fa5694895 fix: remove unused settings_read/settings_write permissions from plugin.json
Only process permission is required for tailscale + clipboard commands.
Least-privilege fix. Fixes #16
2026-05-25 03:00:33 +00:00
b6ead317e1 fix: add running guards to prevent concurrent toggleProcess/exitNodeProcess
Rapid clicks or slow ops no longer spawn duplicate tailscale invocations.
Matches existing pattern used for copyProcess safety.
Fixes #15
2026-05-25 03:00:33 +00:00
42d3bef5c6 fix: capture intended toggle action at click time to avoid stale isConnected in error toast
Store _pendingToggleAction before starting toggleProcess.
Use it in onExited instead of live root.isConnected.
Prevents 'Failed to disconnect' when user actually clicked connect.
Fixes #14
2026-05-25 03:00:33 +00:00
dce33692ad chore: confirm single authoritative error path for statusCheck
parseStatusResult safely catches JSON errors (lib.js:68).
onStreamFinished performs no toasts.
All failure toasts centralized in statusCheck.onExited (TailscaleWidget.qml:103).
Eliminates historical double-toast spam described in #13.
Fixes #13
2026-05-25 03:00:33 +00:00
3d62e4c4b2 fix: remove redundant binaryAvailable guard from TailscaleWidget.qml
Removes stale one-way property, guards, and dead UI branch.
Error handling already covered by Process onExited handlers.
Fixes #11
2026-05-25 03:00:33 +00:00
6385f6b19c Professionalize the author name. 2026-05-25 02:49:59 +00:00
5523738dc5 Added guard against useless state caching anti-pattern AI agents keep insisting on.
Multiple LLMs keep trying to revert issue #11 unless specifically argued against, and keep sneaking it into code. Other, similar examples of this pathological insistence on storing/caching state that offers no tangible benefit warranting the complexity and edge cases have been tried, but headed off by me earlier.
2026-05-21 09:15:27 +00:00
2227cb60fe Merge feature_comprehensive_fixes into vibes 2026-05-21 06:38:23 +00:00
701daa9a39 refactor: replace detectClipboard with try-fallback-cached clipboard strategy
- Remove detectClipboard Process and clipboardCmd property
- Add try-fallback-cached copy logic: attempt cached tool first,
  then cycle through hardcoded safe tools (dms, wl-copy, clipmanctl)
- Add stderr StdioCollector to all Process components for error details
- Update lib.js: replace parseClipboardDetection with validateClipboardTool,
  buildCopyCommand, nextClipboardTool, allClipboardTools
- Update tests to match new lib.js API

Benefits:
- No startup delay from clipboard detection process
- Robust fallback if clipboard tool becomes unavailable
- Better error messages with stderr details from failed commands
2026-05-21 06:37:14 +00:00
cac0ae6bde Merge branch 'feature_sanitize_shell_commands' into vibes 2026-05-21 05:11:17 +00:00
4fbc4e1594 Merge pull request 'Add conduct rules for agents.' (#36) from perf_agent_improvement into master
Reviewed-on: #36
2026-05-21 04:54:10 +00:00
bb50912bb3 Add conduct rules for agents.
Agent frequently ignored `docs/agents/git-workflow.md` instructions. Reiterated critical rules and added a few others to maintain clarity, traceability, and obedience of agents.
2026-05-21 04:54:10 +00:00
f87ade7a67 Merge branch 'feature_sanitize_shell_commands'
Sanitize shell command construction by delegating to lib.js functions:
- validateClipboardCmd: whitelist-based input validation
- buildCopyCommand: safe clipboard command construction
- parseClipboardDetection: safe stdout parsing with fallback
- buildToggleCommand: pure toggle command builder
- parseStatusResult: safe JSON parsing with try/catch
- QML refactor: delegates all shell command building to lib.js
- Expanded clipboard detection to xclip and xsel
- Fixed clipboard detection script to use if/elif/else
2026-05-21 03:57:15 +00:00
2ece3cc103 fix: use if/elif/else in clipboard detection script
The previous &&/|| chain evaluated all commands, producing multi-line
output when multiple tools were installed. parseClipboardDetection
correctly rejected this as invalid, falling back to 'none'. The
if/elif/else structure ensures only the first match is echoed.
2026-05-21 02:36:40 +00:00
6ef933211c fix: expand clipboard detection to xclip and xsel
Add xclip and xsel to the whitelist and detection script so users
on systems without wl-copy or clipmanctl can still copy peer info.
2026-05-21 02:29:13 +00:00
93b257ba5d refactor: delegate shell command construction to lib.js functions
Replace inline shell command building in QML with calls to
parseClipboardDetection, parseStatusResult, buildToggleCommand, and
buildCopyCommand. This centralizes sanitization logic and removes
duplicated try/catch and ternary blocks from the UI layer.
2026-05-20 19:37:08 +00:00