Reading a log file meant copying the configured path out of Settings and
pasting it into a file manager. The Logs directory row now carries an Open
button beside Browse that reveals the folder directly.
The new src/platform/filemanager package holds the platform split — explorer
on Windows, xdg-open on Linux, an "unsupported" error elsewhere — and starts
the handler without waiting on it, since Explorer exits non-zero even after it
opens the window and blocking would stall the UI thread. A missing path, a
path that is a file, and a handler that will not start are all reported to the
user; the logs directory does not exist until the first run, so that case is
reachable.
The button opens whatever the field currently holds rather than the saved
config, so an edit can be checked before Save. Resolving a relative directory
against the application folder is the store's rule, so resolveConfiguredDir is
now exported as storage.ResolveConfiguredDir instead of being duplicated in
the UI.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Each job can now render as a single line — name on the left, status on the
right — instead of the three-line block, so many more jobs fit without
scrolling. A toggle button beside the Folder filter switches between the two
modes and is labelled with the action it performs, matching the existing
"Disable auto" convention.
The choice is persisted as Config.JobListView ("detailed" / "compact", stored
as job_list_view in gosentry.json). Empty, legacy, and unrecognised values all
normalize to detailed, so existing installs keep the current look and the file
never gains a value no reader understands.
Selection, the details panel, the folder filter, and live status updates work
unchanged in both modes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A per-job timeout now has three distinct states: unset inherits the global
default, an explicit 0 means no timeout and does not inherit, and a positive
value is the per-job limit. Job.TimeoutSeconds became *int so unset and 0 stay
distinguishable in jobs.json.
Also fixes the global default, which could not persist a 0. loadOrCreateConfig
normalized DefaultTimeoutSeconds <= 0 back to 30 on every read of an existing
gosentry.json, so "no timeout" only held until the next restart. The field is
now written unconditionally (no omitempty) and read back as-is.
Existing jobs and configs are unaffected: a job with no timeout_seconds still
inherits, and a saved global default of 30 stays 30.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
DefaultTimeoutSeconds now means "no timeout" when 0/empty, and that is
the new default, rather than an invalid config forcing a positive
value. runner.RunJob avoids context.WithTimeout with a zero duration
(which would expire immediately) and instead runs on a plain
cancelable context when no timeout is configured. Per-job
TimeoutSeconds inherit semantics are unchanged.
Add an optional per-job run timeout following the overlap_policy inherit
pattern: Job.TimeoutSeconds (0 = inherit) resolves against a new
Config.DefaultTimeoutSeconds (default 30s), replacing the hard-coded 30s
guard in runner.RunJob.
- domain/storage: new fields, default 30, load-time normalization
- runner: RunJob takes an explicit timeout; StartOnly stays untimed so it
keeps measuring launch latency only
- app: effectiveTimeout resolves under mu into runEnv, threaded to runJob;
seam signature and validation updated; DisplayTimeout helper
- ui: Timeout entry in the job dialog, Default timeout in Settings, and a
Timeout row in the details panel
- tests + docs (ARCHITECTURE, STANDARDS, ROADMAP, CHANGELOG) updated;
version bumped to 0.12.0
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The prior fix switched \n to <br/> in node labels, but Gitea's mermaid
renderer still emits unclosed <br> tags in the generated SVG regardless
of source syntax. Use single-line labels instead to avoid <br> entirely.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replace CODE_REVIEW.md with a living maturity checklist, document
session-only History, inject Service into newMainView for testability,
add UI and scheduler regression tests, and fix RunNow error surfacing
plus empty jobs view handling.
Co-authored-by: Cursor <cursoragent@cursor.com>
StartOnly jobs previously forced DurationMS to 0 because GoSentry does
not wait for the process to exit, leaving the Statistics line stuck at
"last 0 ms, avg 0 ms". The runner already measures launch latency (time
to spawn the process) for the History detail; this now returns that
value as the run duration so the existing duration-driven stats pipeline
folds it into last/avg/max.
Sub-millisecond launches still round to 0 and are excluded from the
average, matching prior behavior.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace overlap Pending flag with PendingRuns counter, match seed stats
by job_id, align average duration with TimedRunCount, and tidy docs.
Co-authored-by: Cursor <cursoragent@cursor.com>
Snapshot store paths under lock before async runs, roll back failed
start/save state, emit UI events only after successful persistence,
surface log write failures, and sync stale YAML docs to JSON.
Co-authored-by: Cursor <cursoragent@cursor.com>
T6.1: split jobs_view.go into three files — jobs_view_helpers.go (pure
helpers) and jobs_view_details.go (detailsPanel struct with widget
creation, update, clear, and container methods) — bringing jobs_view.go
from 459 to ~200 lines.
T6.2: remove stale YAML upgrade note from README; drop *.yaml from
.dockerignore.
T6.3: delete YAML shadow structs (yamlConfig/yamlJob/yamlJobsFile),
importYAMLConfig/importYAMLJobs, legacy path constants, and all
YAML-import tests; run go mod tidy to remove go.yaml.in/yaml/v4.
T6.4: refresh ARCHITECTURE.md — JSON storage references, new Key Domain
Concepts section (per-job overlap policy, run-time statistics + log
seeding, persisted pause flag, jobs_view split).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary
Completed Phase 5 refactoring and reached the target architecture.
**Architectural milestone achieved:**
- Service layer owns all state and is the sole writer
- UI is a thin Fyne view, all widget updates marshaled via `fyne.Do`
- Core engines are stateless and injectable
- Domain types are pure (no `yaml:"-"` fields)
- Full module builds and `go vet ./...` clean
## Changes
- Bump version: 0.3.6 → 0.4.0
- Update CHANGELOG with Phase 5 summary
- Add ROADMAP "Refactoring Follow-Ups" section
## Known follow-up work
1. **Linux test build broken** — `runner_test.go` needs `//go:build windows` tag
2. **File-size limits exceeded** — `operations.go` (486 lines), `jobs_view.go` (415 lines)
See ROADMAP.md for details.
---------
Co-authored-by: mixeme <mix.public@ya.ru>
Reviewed-on: #1
Rename the application, Go module path, command package, build artifacts, resource script, and embedded icon assets from PySentry/pysentry to GoSentry/gosentry.
Move portable settings to gosentry.yaml while reading legacy pysentry.yaml during the transition, then rewrite settings under the new name.
Update Windows and Linux autostart integration to use GoSentry names while cleaning up legacy PySentry registry, desktop-entry, and systemd artifacts.
Refresh README, architecture notes, roadmap, changelog, and release examples for version 0.3.0.
Add a shared --start-in-tray argument that lets autostart start the scheduler and tray integration without opening the main window.
Write the argument into Windows Startup shortcuts and Linux XDG Autostart desktop entries, and verify existing autostart entries include it.
Keep manual launches unchanged and let a manual second launch reveal an already-running instance while duplicate autostart launches stay hidden.
Replace the HKCU Run autostart entry with a per-user Startup folder shortcut. A .lnk stores TargetPath separately, which avoids fragile quoting when the executable path contains spaces.
Remove legacy PySentry and GoSentry Run entries when saving autostart settings, and report shortcut status from the actual shortcut target.
Add Windows tests that create and read a temporary shortcut with spaces in the path so the PowerShell/COM invocation remains covered.
Add Linux desktop integration that installs a user-level .desktop file and icon under XDG data directories so taskbars can match the PySentry window to the application icon.
Pass the installed icon path into Linux autostart desktop entries when available, while keeping the Windows and fallback autostart APIs compatible.
Bump the application version to 0.2.2, update README artifact examples, and record the release notes in docs/CHANGELOG.md. Also adjust the Mermaid architecture diagram so Gitea can render it without invalid SVG line-break tags.
Add ARCHITECTURE.md with a Mermaid component interaction diagram and short descriptions of the main runtime flows.
Move CHANGELOG.md and ROADMAP.md under docs/ so project documentation lives in one place, and update README links plus the project layout description.