summaryrefslogtreecommitdiff
Commit message (Collapse)AuthorAgeFilesLines
* Bump to 3.9.0; reflect shipped work in roadmapChristian Cleberg33 hours2-38/+53
| | | | | | | Cut 3.9.0 (build 94), bundling this session's features. Update ROADMAP.txt: mark hub.sr.ht project writes + discovery (#12-#15) done, correct the Q2 ingest note and App Intent gaps, and reconcile the release plan (3.9.0 is the shipped cut; ingest/deploy keys move to 3.10.0).
* Merge pull request #33 from krazywarez/projects-crudChristian Cleberg34 hours7-2/+1267
|\ | | | | Projects: discovery, create, edit, manage linked resources (#12, #13, #14, #15)
| * Projects: discovery, create, edit, manage linked resources (#12, #13, #14, #15)Christian Cleberg34 hours7-2/+1267
|/ | | | | | | | | | | | | | | | | | | hub.sr.ht's GraphQL now exposes the project write API (create/update/ link/unlink) and a public `projects` discovery query, so these previously-blocked issues can be built. ProjectService gains: fetchPublicProjects (#12); createProject (#13); updateProject with ProjectInput (#14); link/unlink for sources, trackers, and mailing lists plus linkable-resource candidate fetches (#15); and hub cache invalidation after every mutation. UI: a Discover browser and a create form reached from the projects list; an Edit form and a Manage Resources sheet on project detail, gated to projects the user owns. Mutations degrade to a visible error if a field isn't live yet. Built against the master schema; live deployment on sr.ht/query is not yet confirmed (introspection there requires a token).
* Merge pull request #32 from krazywarez/sync-man-pagesChristian Cleberg34 hours6-15/+250
|\ | | | | Sync bundled man page catalog from man.sr.ht (#7)
| * Pin create-pull-request action to a commit SHAChristian Cleberg34 hours1-1/+1
| | | | | | | | | | SonarCloud (githubactions:S7637) flags third-party actions referenced by mutable tag as a supply-chain risk; pin to the v7 commit SHA.
| * Sync bundled man page catalog from man.sr.ht (#7)Christian Cleberg34 hours6-15/+250
|/ | | | | | | | | | | | | | | | The More tab's official man-page list was a hardcoded array, updated by hand. Move it to a checked-in Hutch/Resources/man-pages.json (bundled via the synchronized group) loaded by a new ManPageCatalog, with the previous list kept as a built-in fallback. Add scripts/sync_man_pages.py, which re-derives the catalog from the man.sr.ht landing page, and a weekly scheduled workflow that runs it and opens a pull request when the list diverges upstream. The script refuses to write a suspiciously short list so a markup change can't gut the catalog. This first sync also picks up chat.sr.ht, which upstream added since the list was last hand-edited. Tests cover catalog loading, the fallback, and JSON decoding.
* Merge pull request #31 from krazywarez/app-intents-expansionChristian Cleberg35 hours8-64/+186
|\ | | | | Expand App Intents: dialogs, search type, mutating intents (#17)
| * Expand App Intents: dialogs, search type, mutating intents (#17)Christian Cleberg35 hours8-64/+186
|/ | | | | | | | | | | | | | | | Addresses the three open items on the App Intents ticket: - Check Status / Check Builds now return a spoken/visible dialog alongside their value, so they surface a result in Siri instead of appearing to do nothing. Logic consolidated to always produce a message. - Search Hutch gains a Search Type parameter (user, git/hg repo, mailing list, tracker, build job) threaded through the .search route into Lookup, which pre-selects the type. LookupType now conforms to AppEnum. - Adds mutating intents (not just navigation): Clear Recent Activity and Unpin Resource, backed by RecentActivityStore.clear and a new HomePinStore.removePin. Both act on the active account's storage. Tests cover search-type routing, the blank-query fallback, and pin removal.
* Merge pull request #30 from krazywarez/syntax-highlightingChristian Cleberg35 hours8-29/+377
|\ | | | | Add multi-language syntax highlighting (#16)
| * Add multi-language syntax highlighting (#16)Christian Cleberg35 hours8-29/+377
|/ | | | | | | | | | | | | | | | | Splash (Swift-only, since removed) left code rendering unhighlighted everywhere. Add Highlightr (highlight.js) behind a small SyntaxHighlighter service and use it on both surfaces: - Native file viewer: highlight NSAttributedString by language inferred from the filename, picking a light/dark theme from the trait style and re-highlighting on style changes. Falls back to plain text for unknown languages or very large files. - Markdown/org code blocks in the WKWebView (READMEs, tickets, comments): the web view disables JavaScript, so highlight server-side into inline color-styled spans. The color scheme is now part of the render/cache key since colors are baked into the HTML. Covered by unit tests for language mapping and highlighted output.
* Merge pull request #29 from krazywarez/issues-9-11-18Christian Cleberg36 hours7-19/+135
|\ | | | | Fix checklist rendering, add clear-recent-activity, speed up pull-to-refresh
| * Take inbox unread count off pull-to-refresh path (#9)Christian Cleberg36 hours2-7/+46
| | | | | | | | | | | | | | | | | | | | The inbox count paginates every thread of every subscribed list (~25s), and .refreshable binds the spinner to loadDashboard returning, so pull held for the whole time. Refresh the count in a cancellable background task that updates the badge when it lands, so pull returns once the fast branches settle. The widget / App Intents snapshot refresh, which builds from a throwaway view model, opts back into awaiting inbox so its count stays accurate.
| * Let users clear recent activity on Home (#11)Christian Cleberg36 hours3-1/+80
| | | | | | | | | | | | | | Add a Clear button in the Home Recent section header to drop all entries, plus swipe-to-delete on each row to forget a single item (gated on the existing swipe-actions setting). Back it with RecentActivityStore.clear and remove(id:), with unit tests.
| * Fix checklist rendering with inline code (#18)Christian Cleberg36 hours1-3/+1
| | | | | | | | | | | | | | | | The .task-list-item CSS used display: inline-flex, which turned each text run and inline <code> into separate rigid flex items so a bullet mixing code with text rendered malformed instead of flowing inline. The checkbox is already centered via vertical-align, so switch to plain inline display and let the fragments flow and wrap naturally.
| * Fix bundled resource refs after doc rename to .nfo/.txtChristian Cleberg36 hours1-8/+8
|/ | | | | | | The doc-format conversion renamed README.md->README.nfo and SECURITY.md->SECURITY.txt but left the Xcode resource references pointing at the old filenames, breaking the app build (Ld: SECURITY.md no such file). Point the references at the renamed files.
* convert readme to nfo; convert docs to txt; relicense to 0bsdChristian Cleberg6 days9-783/+86
|
* Update test fixtures to [email protected] emailChristian Cleberg6 days2-5/+5
|
* Update SonarCloud project id, contact emails, and bump to 3.8.5 (93)Christian Cleberg6 days5-18/+18
| | | | | | - Point README badges and ROADMAP query at the krazywarez_hutch SonarCloud project - Change user-facing contact emails to [email protected] (README, SECURITY, About screen) - Bump MARKETING_VERSION to 3.8.5 and CURRENT_PROJECT_VERSION to 93
* Bump marketing version to 3.8.4Christian Cleberg6 days1-6/+6
| | | | The 3.8.3 train is closed for new submissions on App Store Connect.
* update stats endpointChristian Cleberg6 days2-13/+13
|
* update org nameChristian Cleberg6 days4-7/+7
|
* Merge pull request #24 from zerolabsco/remove-splash-highlighterChristian Cleberg14 days3-71/+1
|\ | | | | Remove Splash syntax highlighter dependency
| * Remove Splash syntax highlighter dependencyremove-splash-highlighterChristian Cleberg14 days3-71/+1
|/ | | | | | | | | | | | | | Splash only highlights Swift, leaving every other language unhighlighted. Drop the dependency entirely and render file contents as plain text until a broader-coverage highlighter is adopted. - Remove `import Splash` and the Splash-backed theming in FileTreeView - Simplify CodeSyntaxHighlighter to emit plain attributed text - Remove the Splash SwiftPM package reference and product dependency Refs https://github.com/zerolabsco/hutch/issues/16 Co-Authored-By: Claude Opus 4.8 <[email protected]>
* add app store badge to readmeChristian Cleberg2026-07-161-0/+2
|
* Fix Safari extension manifest for App Store uploadv3.8.2Christian Cleberg2026-07-161-1/+2
| | | | | | The non-persistent background declares scripts without a service_worker, so App Store validation (code 90849) requires the persistent flag to be explicitly false on iOS/iPadOS. Add "persistent": false.
* Merge pull request #20 from zerolabsco/home-status-badgeChristian Cleberg2026-07-164-37/+72
|\ | | | | Move Home system status into a title-bar status badge
| * Move Home system status into a title-bar status badgeChristian Cleberg2026-07-164-37/+72
|/ | | | | | | | | | | | | | | | Replace the disruption-only banner on the Home tab with a persistent circular status indicator in the navigation bar, next to the "Home" title. The badge reflects the existing status logic — green/check when operational, orange/exclamation on disruption, gray otherwise — and taps through to System Status. SystemStatusSummaryRow is unchanged and still used by the More tab. Resolve the system-status result first in HomeViewModel.loadDashboard so the badge settles from cache immediately instead of waiting on the slower projects/jobs/tickets/inbox loads, which had left it spinning for several seconds. Bump MARKETING_VERSION to 3.8.2 and record it in ROADMAP.
* Merge pull request #19 from zerolabsco/docs-dual-forge-trackersChristian Cleberg2026-07-161-0/+2
|\ | | | | docs: note dual-forge issue/patch tracking in README
| * docs: note dual-forge issue/patch tracking in READMEChristian Cleberg2026-07-161-0/+2
|/ | | | | Hutch is hosted on both GitHub and sourcehut as synced peers; tell contributors they can file issues or send patches on either forge.
* Merge pull request #8 from zerolabsco/phase-3-sonarcloud-housekeepingv3.8.1Christian Cleberg2026-07-1614-52/+109
|\ | | | | v3.8.1: SonarCloud triage, forceRefresh fix, housekeeping
| * chore: track the two HutchIntents TODOs in the roadmap (S1135)Christian Cleberg2026-07-162-4/+26
| | | | | | | | | | | | | | | | SearchHutchIntent's route-to-Lookup stopgap and the absent OpenSavedSearchIntent are both gated on a global search/persistence layer Hutch lacks. Promote both to ROADMAP § "App Intent gaps" and replace the inline TODOs with plain references, clearing those two S1135 issues without losing the design intent.
| * fix: move the S1186 empty-block comments inside the bracesChristian Cleberg2026-07-163-3/+3
| | | | | | | | | | | | Trailing // comments after {} left the block lexically empty, so SonarCloud kept flagging stopLoading (and would have re-flagged the two Cancel buttons). S1186 wants a *nested* comment; use /* ... */ inside.
| * chore: record the SonarCloud + housekeeping pass, bump to 3.8.1Christian Cleberg2026-07-162-30/+64
| | | | | | | | | | | | Update the roadmap's SonarCloud section to the live 53-issue / 10-rule reality and mark what v3.8.1 fixed, silenced-as-bug, and left Won't Fix. Bump MARKETING_VERSION on the app, widget, and Safari extension.
| * chore: clear the actionable SonarCloud code smellsChristian Cleberg2026-07-167-11/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | - S1871: merge the identical .home / .recentActivity deep-link cases in RootView — recent activity is a section of Home, not its own screen. - S1186: comment the two intentionally-empty Cancel buttons (PatchsetDetailView, TicketDetailView) and the empty URLProtocol stopLoading override in APICacheTests. - S108: comment the expected-miss catch block in APICacheTests. - S1172: rename the unused url parameter in mimeType(for:) to _. - S4624: extract the nested template literal in the deep-link builders (background.js, content.js) to a pathSegment variable. Left as Won't Fix, with reasons: the 35 hardcoded-URI warnings (a one-forge client and its literal-URL tests), executeCached's 8 params (38 call sites, no benefit), the forceRefresh S1172 pair (fixed as a real bug instead), S1481 on ArtifactsView (false positive — $vm.error is used), and S7785 (top-level await would break a classic content script).
| * chore: move AccountSession.swift out of the stray nested Hutch/Hutch dirChristian Cleberg2026-07-161-0/+0
| | | | | | | | | | | | | | | | It sat at Hutch/Hutch/App/AccountSession.swift, one level too deep. The target is a PBXFileSystemSynchronizedRootGroup rooted at Hutch/, so the file compiled by path with no pbxproj reference; moving it beside the rest of App/ needs no project-file change. Also removed the emptied Hutch/Hutch tree and the stray empty Hutch/HutchTests dir.
| * fix: honor forceRefresh for projects and system status on the dashboardChristian Cleberg2026-07-163-9/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | | loadDashboard(forceRefresh:) fanned the flag out to five loaders, but loadProjects and loadSystemStatusSnapshot dropped it: they called fetchProjects() and snapshotResult() with no policy, so pull-to-refresh returned cached projects and status while the other three sections refreshed. SonarCloud flagged both params as unused (swift:S1172). Thread forceRefresh through ProjectService.fetchProjects into the page policy (refreshIgnoringCache when forced), and pass it to snapshotResult, which already accepted it. ProjectsListView carried the same latent bug via its own .refreshable — fixed there too now that fetchProjects can force.
* | Merge pull request #10 from zerolabsco/ci-no-post-merge-runChristian Cleberg2026-07-161-4/+11
|\ \ | |/ |/| ci: drop the redundant post-merge test run
| * ci: drop the redundant post-merge test runChristian Cleberg2026-07-161-4/+11
|/ | | | | | | | The suite ran on push to main and on pull_request. Since merges here are merge commits (not squash) and pull_request tests the merge result, a green PR already validates the exact tree that lands on main — the push run just re-confirmed it on a macOS runner. Trigger on pull_request (and workflow_dispatch) only.
* docs: bucket the Phase 3 backlog into semantic versionsChristian Cleberg2026-07-161-8/+67
|
* chore: ignore local agent notesChristian Cleberg2026-07-161-0/+5
| | | | | | CLAUDE.md holds working notes for this checkout — build invocation, remote topology, and which mistakes this codebase invites. Project facts stay in ROADMAP.md and SCOPE.md, which are committed.
* docs: record the SonarCloud backlog and the What's cooking taskChristian Cleberg2026-07-162-1/+63
| | | | | | | | | | | | | | | | | | | Two additions to Phase 3. SonarCloud, with the breakdown rather than the headline: 51 open issues are 0 bugs, 0 vulnerabilities and 51 code smells, and 35 of those are hardcoded-URI warnings against a deep-link mapper's test fixtures and a one-forge client's endpoint constants. Those want triaging as Won't Fix, not refactoring. The part worth real thought is the 3 hotspots — the sr.ht token is stored without a SecAccessControl, so an unlocked phone hands it over, which is a product decision rather than a lint nit. Ingesting sr.ht's quarterly "What's cooking" posts, because nothing here tracks the API's evolution and this repo's assumptions rot silently. Already proven worthwhile: SCOPE.md claimed pronouns were not in the schema while AppState queries them and UserProfileView displays them. That entry is struck through and kept as evidence. Q2 2026 also reports a writable hub.sr.ht API and finished deploy keys, both of which contradict what is written here.
* Merge pull request #6 from zerolabsco/phase-3-api-featuresChristian Cleberg2026-07-1619-74/+944
|\ | | | | Phase 3: API features
| * chore: remove the artifacts debug probev3.8.0Christian Cleberg2026-07-161-18/+0
| | | | | | | | | | It did its job: tags=1 confirmed the menu was disabled by its own tags check while the explanation sat unreachable inside it.
| * fix: deleted repositories linger until the cache expiresChristian Cleberg2026-07-162-1/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Deleting a repository left it on the list, and pulling to refresh did not shift it. Two independent reasons, both cache-related. deleteRepository never invalidated anything. Creation invalidates the repositories and home prefixes; deletion was written without it, so the list and Home kept serving a repository that no longer exists. And forceRefresh only ever reached the build statuses — its own doc comment says so — while the repository list itself was pinned to useCache: true. So a pull to refresh re-served the same cache it already had. fetchPage already takes useCache and falls through to an uncached fetch; it was simply never told.
| * fix: download artifacts through the API instead of handing them to SafariChristian Cleberg2026-07-163-2/+87
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Tapping download opened Artifact.url in the browser, which answered with "Authorization header is required". That URL is not a web page: git.sr.ht resolves it to <api origin>/query/artifact/<checksum>/<filename>, which demands a bearer token. Safari has none and no way to get one, so the download could never have worked — this predates the upload work. Fetch it with the client that already holds the token and hand the user the file through a share sheet. fetchData mirrors fetchText, including its host guard, so an authenticated request still cannot be aimed anywhere but *.sr.ht over https. Also guards zero-byte uploads. sr.ht streams into S3, which rejects a zero-part multipart completion with "MalformedXML: UnknownError" — an error that says nothing about the cause and cost a round of testing to identify. Empty files are now refused by name before the request is made.
| * fix: make artifact upload actually fire, and show it when it failsChristian Cleberg2026-07-161-10/+37
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Picking a file did nothing. The fileImporter's isPresented binding was derived from uploadTargetRef and nilled it on dismissal, but dismissal happens before the completion runs — so the completion read nil and returned without uploading. Presentation state and payload state cannot be the same state. A plain isImporting bool drives presentation now; the tag survives in uploadTargetRef until the completion consumes it. The upload menu was also disabled when the repository has no tags, while the explanation for that state lived inside the menu — unreachable exactly when it applies, so the tap died with no reason given. sr.ht requires revspec to match a tag, so having none is a real state worth explaining rather than hiding. Failures were invisible too. uploadArtifact and deleteArtifact set error, but the overlay only renders it when the list is empty, so a rejection on a repository that already has artifacts — a duplicate filename is the likely one, since sr.ht requires filenames to be unique per repository — set an error nobody saw. The tab carries an error banner now.
| * fix: push mailing lists locally, fix upload menu, drop the events feedChristian Cleberg2026-07-1610-346/+52
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Opening a mailing list from More → Projects still blanked. The cause was not in handleTabNavigation: the row called openMailingList and then dismiss(), so a path rebuild and a pop of this very view raced each other. Projects already lives in the More tab, so there is nothing to navigate to — push MailingListDetailView directly, which also lands back on the project rather than on Mailing Lists. Sources and trackers keep routing, because they really do land in other tabs. The upload controls did nothing. Two .confirmationDialog modifiers on one view leave one silently dead, and this view already had one for delete, so the tag picker never presented. It is a Menu now, which also puts the tags one tap away instead of two. The ticket activity feed is removed. todo.sr.ht's root events resolver joins event.participant_id, which references participant(id), against participant.user_id — different id spaces — so it returns an empty list for every user. The rows exist; that join cannot find them. Ticket.events is unaffected because it filters on ticket_id, which is why ticket timelines work. No client can fix this, and a screen that is permanently empty while blaming the token's scopes is worse than no screen. Recorded in SCOPE.md with the query.
| * fix: blank mailing list from Projects, swipe flicker, hidden uploadChristian Cleberg2026-07-166-46/+69
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Three problems from manual testing. Opening a mailing list from More → Projects showed a blank screen, while the same tap on a project pinned to Home worked. handleTabNavigation reset the target path and appended to it two Task.yields later. When the target tab is already on screen — Projects lives under More — the reset starts an animated pop of the view the user is standing on and the appends land mid-animation. From Home the tab actually changes, so the More stack is quiescent and the appends land cleanly. Each case now builds its path and assigns it once, so SwiftUI gets a single diff with nothing to race. Destructive swipe actions made the row vanish and spring back while the confirmation was still up. role: .destructive makes SwiftUI perform the row removal on activation, which allowsFullSwipe: false does not prevent — the report was a tap, not a full swipe. These buttons only record pending state and wait for an answer, so they are plain buttons tinted red instead. Six sites: the two added here, plus trackers, pastes, and tracker ACLs and labels, which had the same flicker already. The artifacts upload control was invisible. It was declared as a toolbar item from a view that is a segment inside RepositoryDetailView's tab switch rather than its own navigation destination, so it never reached the navigation bar. It is a row in the list now, and also an action on the empty state — the overlay covers the list, and a repository with no artifacts is precisely the one that needs uploading.
| * fix: stop destructive swipes animating rows out before confirmationChristian Cleberg2026-07-162-2/+8
| | | | | | | | | | | | | | | | | | | | | | Swiping to delete made the row vanish and then spring back while the confirmation was still on screen. A destructive swipe action left to full-swipe performs itself on the gesture and animates the row away, but these actions only set pending state and wait for an answer, so the row returned when the data had not changed. allowsFullSwipe: false, which PasteListView already uses for exactly this confirm-then-delete shape. Both new swipes had the same omission.
| * chore: bump to 3.8.0 and record Phase 3 API featuresChristian Cleberg2026-07-164-29/+71
| | | | | | | | | | | | | | | | | | | | | | | | MARKETING_VERSION 3.7.0 -> 3.8.0, build 89 -> 90. SCOPE.md gains the items that did not survive contact with the API: archiveMessage and mailingListSubscribe are blocked, while webhooks, shareSecret, and build groups are reachable but declined on judgement. The reasoning is recorded so they do not get re-proposed as gaps. ROADMAP.md notes that Phase 3 is several releases rather than one, with the measured size of each.