Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@

All notable changes to kuri are documented here.

## [0.4.12] — 2026-07-25

A hotfix for two problems that made the *installed* product diverge from the built one.

### Fixes

- **The installer never installed `kuri-mobile`.** `install.sh` copied out `kuri`, `kuri-agent`, `kuri-fetch` and `kuri-browse` — but not `kuri-mobile`, which has shipped inside the release tarball since 0.4.6. Because `kuri android` and `kuri ios` exec it as a *sibling* binary, every install since then left those subcommands failing with `failed to exec 'kuri-mobile'` despite a successful-looking install. Four releases of mobile work were undeliverable through the documented install path

### Features

- **`kuri update`** (alias `kuri upgrade`). Previously the only way to upgrade was to remember an installer URL and pipe it to a shell; `kuri update` was simply an unknown argument. It reads the stable channel manifest, compares the published version against the one compiled in, and installs if they differ
- `--check` reports what would happen and changes nothing
- `--dir=<path>` overrides the destination; by default it installs next to the running binary, so an update replaces *this* install rather than creating a second one that may or may not win on PATH
- The SHA-256 is verified **in process** rather than shelled out. `install.sh` tries `shasum`, then `sha256sum`, then `openssl`, and silently skips verification when none is present — a verification step that depends on what happens to be on PATH is one that can quietly not happen
- Binaries are installed by writing a temp file beside the target and `rename`-ing over it. Copying onto a running executable fails with `ETXTBSY` on Linux and can corrupt a concurrently-executing image elsewhere; rename is atomic and leaves the running process on its old inode
- `curl` is used purely as transport, deliberately: routing this through the in-tree TLS stack would let a TLS regression break the one command meant to repair it

## [0.4.11] — 2026-07-25

### Fixes — kuri no longer takes over your machine
Expand Down
2 changes: 1 addition & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.{
.name = .kuri,
.version = "0.4.11",
.version = "0.4.12",
.dependencies = .{
.quickjs = .{
.url = "https://github.com/mitchellh/zig-quickjs-ng/archive/main.tar.gz",
Expand Down
6 changes: 5 additions & 1 deletion install.sh
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,11 @@ tar -xzf "$TMP/kuri.tar.gz" -C "$TMP"
# ── Install binaries ──────────────────────────────────────────────────────────
mkdir -p "$INSTALL_DIR"

BINS="kuri kuri-agent kuri-fetch kuri-browse"
# kuri-mobile must be here: `kuri android`/`kuri ios` exec it as a *sibling*
# binary, so omitting it leaves those subcommands failing with "failed to exec"
# on an otherwise successful install. It shipped in the tarball from v0.4.6 but
# was missing from this list until v0.4.12.
BINS="kuri kuri-agent kuri-fetch kuri-browse kuri-mobile"
INSTALLED=""
for BIN in $BINS; do
if [ -f "$TMP/$BIN" ]; then
Expand Down
2 changes: 1 addition & 1 deletion kuri-mobile/build.zig.zon
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.{
.name = .kuri_mobile,
.version = "0.4.11",
.version = "0.4.12",
.dependencies = .{},
.fingerprint = 0x41cfa5929f72d020,
.minimum_zig_version = "0.17.0-dev.813+2153f8143",
Expand Down
2 changes: 1 addition & 1 deletion kuri-mobile/src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub fn main(init: std.process.Init.Minimal) !void {
return;
}
if (std.mem.eql(u8, sub, "--version")) {
try writeStdout("kuri-mobile 0.4.11\n");
try writeStdout("kuri-mobile 0.4.12\n");
return;
}

Expand Down
2 changes: 1 addition & 1 deletion src/browse_main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const markdown = @import("crawler/markdown.zig");
const validator = @import("crawler/validator.zig");
const http_fetch = @import("util/http_fetch.zig");

const version = "0.4.11";
const version = "0.4.12";
const user_agent = "kuri-browse/" ++ version;

pub fn main(init: std.process.Init.Minimal) !void {
Expand Down
2 changes: 1 addition & 1 deletion src/fetch_main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const markdown = @import("crawler/markdown.zig");
const js_engine = @import("js_engine.zig");
const http_fetch = @import("util/http_fetch.zig");

const version = "0.4.11";
const version = "0.4.12";

pub fn main(init: std.process.Init.Minimal) !void {
var gpa_impl: std.heap.DebugAllocator(.{}) = .init;
Expand Down
34 changes: 33 additions & 1 deletion src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ const Bridge = @import("bridge/bridge.zig").Bridge;
const launcher = @import("chrome/launcher.zig");
const api_token = @import("server/api_token.zig");
const lifecycle = @import("lifecycle.zig");
const updater = @import("update.zig");

const version = "0.4.11";
const version = "0.4.12";

const CliAction = enum {
run,
help,
version,
mobile,
token,
update,
};

pub fn main(init: std.process.Init.Minimal) !void {
Expand Down Expand Up @@ -57,6 +59,22 @@ pub fn main(init: std.process.Init.Minimal) !void {
compat.writeToStdout("\n");
return;
},
.update => {
var opts: updater.Options = .{};
for (args[2..]) |a| {
if (std.mem.eql(u8, a, "--check")) {
opts.check_only = true;
} else if (std.mem.startsWith(u8, a, "--dir=")) {
opts.dir = a["--dir=".len..];
} else {
printUnknownArgument(a);
std.process.exit(1);
}
}
const code = try updater.run(gpa, version, opts);
if (code != 0) std.process.exit(code);
return;
},
.run => {},
}

Expand Down Expand Up @@ -135,6 +153,13 @@ fn parseCliAction(args: []const []const u8) !CliAction {
return .token;
}

// `upgrade` is accepted too: it is what half of people type, and failing
// an upgrade command over vocabulary is a poor way to meet a user who is
// trying to get onto a newer version.
if (std.mem.eql(u8, args[1], "update") or std.mem.eql(u8, args[1], "upgrade")) {
return .update;
}

return error.UnknownArgument;
}

Expand Down Expand Up @@ -189,6 +214,7 @@ fn printUsage() void {
\\ kuri android <cmd> Drive Android devices (delegates to kuri-mobile)
\\ kuri ios <cmd> Drive iOS sims/devices (delegates to kuri-mobile)
\\ kuri token Print the API token (creates one if missing)
\\ kuri update Update to the current release (--check to only report)
\\ kuri -h, --help Show this help
\\ kuri -V, --version Print version and exit
\\
Expand Down Expand Up @@ -229,6 +255,11 @@ test "parseCliAction recognises token subcommand" {
try std.testing.expectEqual(CliAction.token, try parseCliAction(&.{ "kuri", "token" }));
}

test "parseCliAction recognises update and its upgrade alias" {
try std.testing.expectEqual(CliAction.update, try parseCliAction(&.{ "kuri", "update" }));
try std.testing.expectEqual(CliAction.update, try parseCliAction(&.{ "kuri", "upgrade" }));
}

test "parseCliAction rejects unknown argument" {
try std.testing.expectError(error.UnknownArgument, parseCliAction(&.{ "kuri", "--wat" }));
}
Expand Down Expand Up @@ -262,4 +293,5 @@ test {
_ = @import("storage/local.zig");
_ = @import("storage/auth_profiles.zig");
_ = @import("util/tls.zig");
_ = @import("update.zig");
}
Loading
Loading