mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-14 10:39:32 +01:00
ea23445ad7010c06eeb48290bf1b243c2ab91be7
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
94912241bc |
feat(desktop): sign-macos.sh signs, notarizes and staples the app and its DMG
The release DMG is signed with the owner's Developer ID and notarized, so a
downloaded copy opens after macOS's usual confirmation instead of stopping at
Gatekeeper. The work is a script of its own, so CI and a Mac run it the same way:
SIGN_IDENTITY=... NOTARY_PROFILE=<profile> \
packages/desktop/scripts/sign-macos.sh <Codeman.app> <out-dir>
It re-signs the app with the hardened runtime, a secure timestamp and
macos/entitlements.plist, checks the signature is a Developer ID one with the
runtime flag, has notarytool notarize it and staples the ticket, builds the DMG
around the stapled app, signs it, notarizes and staples it too, and has spctl
assess both. Codeman.dmg and Codeman.dmg.sha256 reach <out-dir> only after every
check passed; a failed run removes an older pair there rather than leave one to
upload by mistake. A submission Apple does not accept stops the script with its
id and Apple's log. The notary login is either a notarytool keychain profile
(NOTARY_PROFILE, NOTARY_KEYCHAIN) or APPLE_ID, APPLE_APP_PASSWORD and
APPLE_TEAM_ID; `sign-macos.sh --check` tests that without doing anything.
The DMG layout (the app next to an /Applications link, UDZO, volume "Codeman")
moves to make-dmg.sh, which both scripts call, and gains a retry: hosted macOS
runners now and then fail hdiutil create with "Resource busy". bundle-macos.sh
keeps its SIGN_IDENTITY path as it was; its new --notarize checks the
environment before building, then hands the app to sign-macos.sh.
packages/desktop/README.md says the release DMG is notarized and how to do
the same by hand, and drops the CI build and notarization from its ideas list.
All three scripts are bash 3.2 clean, and shellcheck reports nothing. With the
macOS tools stubbed, sign-macos.sh was run under bash 3.2 through a full
signing, a notarization rejected for the app and for the DMG, two hdiutil
failures then a pass, three failures, a relative out-dir and every missing
setting.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
92797c2619 |
test(desktop): unit tests for main.rs's decisions and a browser test for the connect page
main.rs was the only source file without tests, and it held three decisions with real failure modes: - Which login a connect goes out with. The choice was a closure body inside the probe worker; it is now choose_login, tested for every row: typed wins, then the Keychain, then the local Codeman's own login, which is used only when no saved password was expected and only for the same username. - What the Keychain keeps afterwards (update_keychain): saved or deleted by Remember, never a copy of the local server's login, never a password the server wants changed, and the old user's item deleted before the new save. The in-memory Keychain store moves out of credentials' test module so other test modules can use it. - When a commit in the main window means the server page is loaded. The connect page had only substring checks in the repository; the checks that drove it lived in a scratch script. They are now test/desktop-connect-page.browser.test.ts: Chromium, the page's real CSP, a stubbed native side, five ordered walks through every state of both tabs (first run, logins, failures, redirects, Start, the install wait, the SSH install, layout, double clicks, keys, a starting server, a WebKit too old). Listed in BROWSER_TEST_GLOBS, so the nightly browser suite runs it and `npm test` does not. Also pins the install one-liner the page shows to the one Copy copies. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
a42ce9c79f |
fix(desktop): a starting server, windows that open where expected, and the review's smaller findings
Found by the three-part review of this branch. Each was checked against the source first; every decision that can run without a window has a unit test. This Mac: - A Codeman that runs but listens nowhere yet (the first seconds after login, a restart) was reported as "already running ... it listens at process N, which this app cannot open", and Start was refused for it. It is now its own state: the tab says "starting", looks again every second, and opens Codeman once it is up when a connect to this Mac had just been refused. The state table is a pure function with a test (setup::local_state). - A server the app starts runs in the home folder, like one started by launchd or in a terminal. It ran in the app's own directory (`/` after a Finder launch), which Codeman then used as the default for sessions. - Server detection accepts any entry word that `web` follows, so a dev server under a folder named codeman is seen and never gets a second server beside it. - A login shell is polled from 5 ms up instead of every 100 ms, and the port after a launchd start every 100 ms instead of 500: both were pure waiting. - The last line of stdout is no longer glued to the first line of stderr. Addresses and policy: - A tailnet name typed with a port gets http://, not https://. With a port it is Codeman's own listener; https there ended in a TLS error with no hint. - within_base refuses `..%2F` and the other encoded ways out of the base path, so a sibling app behind a decoding proxy never sees the login. - A status answer whose body stalls is a timeout, not "something else answers here". - The folder pop-out pattern matches the two routes the server has. - A malformed `window` in desktop.json no longer costs the server list. Windows: - Pop-outs step off the window in use. tao centres a window with no position, so every pop-out opened exactly on top of the one before. - A window opened by a script no longer brings the app to the front: wry activated the application for it, whatever the window itself was told. - The first-run window sits between the menu bar and the Dock. Centred in the whole display, its bottom was under the Dock on a 900 pt high one. - The window frame is saved once after a move or resize ends, not once a second during the drag. Also makes the connect page independent of TextEncoder and scrollIntoView, so it runs in jsdom as well as in a web view. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
116db3ba66 |
fix(desktop): a connect page that holds still, answers a press and never strands the user
Layout: - The header no longer moves. The page was centred with align-items, so every change of the card's height moved everything (up to 150px between states), and a page taller than its window lost its top above the scroll origin, where no scrolling reaches it. The top margin is now fixed, the card grows downward and has a minimum height, and the page scrolls from its top. A short window gets a compact header. - The status line sits right under the action it reports on, above the "not installed there yet?" section, takes no room while empty, and is scrolled into view in a small window. It was below the fold there. - Looking at this Mac again keeps what was found on screen (the pane used to collapse to "Looking..." and grow back). Feedback and keys: - Buttons answer hover and press, every control shows keyboard focus, the primary button and the footer meet WCAG AA contrast, "Opening Codeman" keeps its spinner while the server page loads. - Return opens or starts the Codeman on this Mac, Esc cancels a connect. Install always takes a click. - The This Mac result is a live region, Forget buttons are named after their server, a long unbroken token wraps inside the card, the status text can be selected. Correctness: - The second click of a double click acts only on the control that took the first. It could connect to the server that slid under the pointer after a Forget, or flip "Connect automatically". - An address, username or password too long for the app is refused with a reason. The app drops such a message without an answer, which left the page on "Connecting..." (the limits are pinned to policy.rs by a test). - A connect answer goes to the tab that asked, a failed SSH install to its tab, and the login block no longer claims a saved password for another server. - An automatic connect to the Codeman on this Mac no longer looks at this Mac first; a failed connect, Cancel or an error asks for that look. - A login over plain http:// to another machine says that it is unencrypted. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
01d3379b74 |
fix(desktop): recover a crashed page, name every dialog's frame, and four smaller review fixes
The findings of the 2026-11-05 review of this branch, each with a unit test where the code can be tested without a window: - A window whose web content process ended (a WebKit crash, or macOS taking the process back under memory pressure) stayed blank: wry answers WebKit's notice itself, which turns WebKit's own reload off. The window now loads its page again. A second end within 30 seconds sends the main window back to the connect page and closes a pop-out, so it cannot loop (policy::recovery). - A JavaScript dialog from a frame nothing names (about:srcdoc, a data: or blob: URL under an opaque origin) showed the page's text as its bold first line. The first line is now always the app's own, the "embedded" flag is set when the origin names no host (it was the wrong way round), and every sub-frame counts as embedded, a trusted web tab on Codeman's origin included. - The connect page lost the text of an error that needs the login fields: the tab switch cleared the status it had just set. - Start for http://localhost:PORT missed the LaunchAgent (the compare was exact against 127.0.0.1) and ran a second, unsupervised server on its port. - The path picker's preview Open link (api/filesystem/preview) did nothing: it was the one page Codeman opens in a window that the allowlist lacked. - The port of a running install was lost whenever the Terminal script that wraps the installer came first in ps. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
8ba5134174 |
feat(desktop): native macOS app that runs, installs or connects to Codeman
Adds packages/desktop, a small native app (Rust: tao, wry/WKWebView, muda, objc2) that opens Codeman in its own window. The universal app is about 5 MB (3.2 MB as a DMG) and runs on macOS 11.3 or later. - Connect screen with two tabs. This Mac finds the local Codeman and offers Open, Start or Install. Start uses launchd for a LaunchAgent install and codeman web -d otherwise. It never starts a second server while one runs, because two servers on one data dir share live sessions. Another machine connects by address (recent servers, Keychain logins) and can install Codeman there over SSH. - Installs run Codeman's install.sh in Terminal from a self-deleting .command script. The installer needs a terminal for sudo, Homebrew and ssh. A local install uses --local --service and the first free port from 3000, and the app opens Codeman once it answers. - The local Codeman's login is read from its LaunchAgent or ~/.codeman/.env. It is sent only to 127.0.0.1 on that port, only while the user's own Codeman process holds it, and is never saved. - Native JS dialogs (alert, confirm, prompt) and HTTP Basic challenge answers, both scoped to Codeman's own pages, so the page keeps working after a server restart. App cookies are cleared before every connect. - Pop-outs through window.CodemanHost, with an allowlist (webview/ never opens a window), external links in the default browser, downloads to ~/Downloads, real full screen and window state that is remembered. - The connect page refuses a WebKit older than Safari 16.4, which Codeman's terminal needs. Codeman side: viewSubagentTranscript shows a toast when the pop-up is refused instead of failing, with zh-CN strings and a test that pins them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |