diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index b5c477ca..80e30958 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -10,7 +10,7 @@ body: id: version attributes: label: T4 Code version - placeholder: "0.1.15" + placeholder: "0.1.16" validations: required: true - type: dropdown diff --git a/README.md b/README.md index 2bafa3ae..a72acf88 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,13 @@ T4 Code is a free, open-source (MIT) desktop app for [Oh My Pi](https://github.c ![T4 Code main window](docs/assets/t4-code-main.png) -[**Download v0.1.15**](https://github.com/LycaonLLC/t4-code/releases/tag/v0.1.15) · [**Docs**](https://t4code.net/docs) · [**Get the source**](#build-from-source) +[**Download v0.1.16**](https://github.com/LycaonLLC/t4-code/releases/tag/v0.1.16) · [**Docs**](https://t4code.net/docs) · [**Get the source**](#build-from-source) ## Requirements -T4 Code needs an OMP build with desktop appserver support. For v0.1.15, use the public integration build below. +T4 Code needs an OMP build with desktop appserver support. For v0.1.16, use the public integration build below. -T4 Code v0.1.15 was verified with OMP 16.5.2 built from [`f9322817`](https://github.com/lyc-aon/oh-my-pi/commit/f9322817981e16bf3f1e3d77684f4269f026aa64), tagged [`t4code-16.5.2-appserver-2`](https://github.com/lyc-aon/oh-my-pi/tree/t4code-16.5.2-appserver-2). That public integration is based on the official upstream [`v16.5.2`](https://github.com/can1357/oh-my-pi/tree/v16.5.2) tag at [`7d02778c`](https://github.com/can1357/oh-my-pi/commit/7d02778c60f4b5db60f84bedbca79d6e64cb91f5). It carries forward T4's appserver, lifecycle, image, session-control, and atomic maintenance integration, then adds bounded child-agent transcript streaming. Tool results preserve sanitized structured details, subagent RPC reads have byte and record ceilings, and child-transcript image digests use the same verified image-read path as the parent session. The official upstream v16.5.2 tag has no `appserver` command, so it cannot host T4 Code. The verified runtime is a normal build from the public `lyc-aon/oh-my-pi` source; T4 Code does not depend on private home-directory files, an auth broker, or a custom Codex CLI fork. T4 Code vendors `@oh-my-pi/app-wire` 0.5.5 from integration commit [`6a87fa64`](https://github.com/lyc-aon/oh-my-pi/commit/6a87fa6407ebff20417b4d52885a6bb3091003ea), source tree `a2495fe8781c979184fe7fb9a6d37d8f33bad30f`. +T4 Code v0.1.16 was verified with OMP 16.5.2 built from [`264958b2`](https://github.com/lyc-aon/oh-my-pi/commit/264958b23acac16baaf3bf0024129dc1a57f9d14), tagged [`t4code-16.5.2-appserver-4`](https://github.com/lyc-aon/oh-my-pi/tree/t4code-16.5.2-appserver-4). That public integration is based on the official upstream [`v16.5.2`](https://github.com/can1357/oh-my-pi/tree/v16.5.2) tag at [`7d02778c`](https://github.com/can1357/oh-my-pi/commit/7d02778c60f4b5db60f84bedbca79d6e64cb91f5). The transcript behavior introduced in appserver-2 remains unchanged: tool results preserve sanitized structured details, subagent RPC reads have byte and record ceilings, and child-transcript image digests use the same verified image-read path as the parent session. Appserver-4 fixes the appserver clean-source TypeScript/build check and makes the appserver type check plus full runtime tests mandatory before OMP release binaries can publish. It also carries forward T4's appserver, lifecycle, image, session-control, and atomic maintenance integration. The official upstream v16.5.2 tag has no `appserver` command, so it cannot host T4 Code. The verified runtime is a normal build from the public `lyc-aon/oh-my-pi` source; T4 Code does not depend on private home-directory files, an auth broker, or a custom Codex CLI fork. T4 Code vendors `@oh-my-pi/app-wire` 0.5.5 from integration commit [`6a87fa64`](https://github.com/lyc-aon/oh-my-pi/commit/6a87fa6407ebff20417b4d52885a6bb3091003ea), source tree `a2495fe8781c979184fe7fb9a6d37d8f33bad30f`. | Platform | Arch | Package | | -------- | --------------------- | ---------------------------------------- | @@ -18,21 +18,21 @@ T4 Code v0.1.15 was verified with OMP 16.5.2 built from [`f9322817`](https://git | Linux | x86_64 | `.deb`, AppImage | | macOS | Apple Silicon (arm64) | `.dmg`, `.zip` (**unsigned, see below**) | -No Windows build and no Intel Mac build in v0.1.15. The iOS TestFlight build is coming soon. +No Windows build and no Intel Mac build in v0.1.16. The iOS TestFlight build is coming soon. -## What changed in v0.1.15 +## What changed in v0.1.16 -- Known tools now have dedicated transcript views for patches, task lists, child-agent work, file reads, shell commands, searches, and fetched sources. Arguments and structured results stay readable without opening raw JSON. -- The Agents pane follows child-agent transcript events and hydrates durable transcript records on demand. It uses the same message, tool, and image components as the main transcript. -- The matching OMP runtime preserves sanitized structured tool details, bounds subagent transcript reads by bytes and records, and serves authorized child-transcript images through the established image path. -- The release keeps the verified atomic maintainer and Android identity checks introduced in the previous release. +- This follow-up release pins T4 Code to the exact appserver-4 runtime source and keeps the tool-aware transcript and child-agent behavior shipped in v0.1.15. +- Appserver-4 fixes its clean-source TypeScript/build check so the appserver package is checked from a fresh checkout. +- OMP release binaries now require the appserver type check and full runtime tests to pass before publication. +- App-wire remains at 0.5.5; no wire-format change is required for this release. ## Install ### Android 1. On the Android phone, sign in to Tailscale with an account that can reach the T4 Code host. -2. Download [`T4-Code-0.1.15-android.apk`](https://github.com/LycaonLLC/t4-code/releases/download/v0.1.15/T4-Code-0.1.15-android.apk). +2. Download [`T4-Code-0.1.16-android.apk`](https://github.com/LycaonLLC/t4-code/releases/download/v0.1.16/T4-Code-0.1.16-android.apk). 3. If Android asks, allow your browser or file manager to install unknown apps, then install the APK. 4. Open T4 Code and enter the host's HTTPS Tailscale address, including its port. @@ -41,8 +41,8 @@ The APK does not contain an appserver or expose one to the public internet. It c ### Linux (Debian/Ubuntu) ```sh -wget https://github.com/LycaonLLC/t4-code/releases/download/v0.1.15/T4-Code-0.1.15-linux-amd64.deb -sudo apt install ./T4-Code-0.1.15-linux-amd64.deb +wget https://github.com/LycaonLLC/t4-code/releases/download/v0.1.16/T4-Code-0.1.16-linux-amd64.deb +sudo apt install ./T4-Code-0.1.16-linux-amd64.deb ``` Use `apt install` rather than `dpkg -i` so system dependencies resolve automatically. @@ -50,17 +50,17 @@ Use `apt install` rather than `dpkg -i` so system dependencies resolve automatic ### Linux (AppImage) ```sh -wget https://github.com/LycaonLLC/t4-code/releases/download/v0.1.15/T4-Code-0.1.15-linux-x86_64.AppImage -chmod +x T4-Code-0.1.15-linux-x86_64.AppImage -./T4-Code-0.1.15-linux-x86_64.AppImage +wget https://github.com/LycaonLLC/t4-code/releases/download/v0.1.16/T4-Code-0.1.16-linux-x86_64.AppImage +chmod +x T4-Code-0.1.16-linux-x86_64.AppImage +./T4-Code-0.1.16-linux-x86_64.AppImage ``` ### macOS (Apple Silicon) > [!WARNING] -> **The macOS v0.1.15 build is unsigned and unnotarized.** Apple has not signed or notarized it, so Gatekeeper can report a "damaged" app or an unidentified developer. Only continue if you trust the release from this repository. You can always build from source instead. +> **The macOS v0.1.16 build is unsigned and unnotarized.** Apple has not signed or notarized it, so Gatekeeper can report a "damaged" app or an unidentified developer. Only continue if you trust the release from this repository. You can always build from source instead. -1. Download [`T4-Code-0.1.15-mac-arm64.dmg`](https://github.com/LycaonLLC/t4-code/releases/download/v0.1.15/T4-Code-0.1.15-mac-arm64.dmg) (or [`T4-Code-0.1.15-mac-arm64.zip`](https://github.com/LycaonLLC/t4-code/releases/download/v0.1.15/T4-Code-0.1.15-mac-arm64.zip)). +1. Download [`T4-Code-0.1.16-mac-arm64.dmg`](https://github.com/LycaonLLC/t4-code/releases/download/v0.1.16/T4-Code-0.1.16-mac-arm64.dmg) (or [`T4-Code-0.1.16-mac-arm64.zip`](https://github.com/LycaonLLC/t4-code/releases/download/v0.1.16/T4-Code-0.1.16-mac-arm64.zip)). 2. Drag `T4 Code.app` into `/Applications`. 3. If Gatekeeper blocks the app and you choose to proceed, remove the quarantine attributes from the copied app bundle: diff --git a/SECURITY.md b/SECURITY.md index 48532608..f207d7ea 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -26,4 +26,4 @@ We read every report and will reply to tell you what happens next. This is a sma - T4 Code is a desktop client. The OMP runtime is a separate project; runtime vulnerabilities belong at . - Pairing credentials are encrypted with the OS keychain via Electron `safeStorage`. Reports about credential handling, the pairing flow, or the `t4-code://` deep-link handler are especially welcome. -- The macOS v0.1.15 build is unsigned and unnotarized; that is a known, disclosed limitation, not a vulnerability report. Removing `com.apple.quarantine` changes Gatekeeper handling but does not sign, notarize, or verify the app. +- The macOS v0.1.16 build is unsigned and unnotarized; that is a known, disclosed limitation, not a vulnerability report. Removing `com.apple.quarantine` changes Gatekeeper handling but does not sign, notarize, or verify the app. diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 77a8274d..805cb2c5 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@t4-code/desktop", - "version": "0.1.15", + "version": "0.1.16", "private": true, "type": "module", "main": "dist-electron/main.cjs", diff --git a/apps/desktop/src/target-manager.ts b/apps/desktop/src/target-manager.ts index 98aaa049..9c20fd94 100644 --- a/apps/desktop/src/target-manager.ts +++ b/apps/desktop/src/target-manager.ts @@ -339,7 +339,7 @@ export class DesktopTargetManager { capabilities: requestedCapabilities, requestedFeatures: REQUESTED_FEATURES, compatibilityRequestedFeatures: COMPATIBILITY_FEATURES, - client: { name: "T4 Code", version: "0.1.15", build: "desktop", platform: process.platform }, + client: { name: "T4 Code", version: "0.1.16", build: "desktop", platform: process.platform }, reconnect: { attemptCap: 12, baseMs: 250, maxMs: 10_000 }, }; const client = createOmpClient(clientOptions); diff --git a/apps/mobile/capacitor.config.json b/apps/mobile/capacitor.config.json index af50fbc4..c280a95d 100644 --- a/apps/mobile/capacitor.config.json +++ b/apps/mobile/capacitor.config.json @@ -3,7 +3,7 @@ "appName": "T4 Code", "webDir": "dist", "loggingBehavior": "debug", - "appendUserAgent": " T4CodeMobile/0.1.15", + "appendUserAgent": " T4CodeMobile/0.1.16", "android": { "path": "android", "minWebViewVersion": 60, diff --git a/apps/mobile/package.json b/apps/mobile/package.json index 40fa67de..04f78581 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -1,6 +1,6 @@ { "name": "@t4-code/mobile", - "version": "0.1.15", + "version": "0.1.16", "private": true, "type": "module", "scripts": { diff --git a/apps/site/package.json b/apps/site/package.json index 603613c3..130539a1 100644 --- a/apps/site/package.json +++ b/apps/site/package.json @@ -1,6 +1,6 @@ { "name": "@t4-code/site", - "version": "0.1.15", + "version": "0.1.16", "private": true, "type": "module", "scripts": { diff --git a/apps/site/src/release.ts b/apps/site/src/release.ts index f92b9a7f..8560608d 100644 --- a/apps/site/src/release.ts +++ b/apps/site/src/release.ts @@ -6,15 +6,15 @@ export const DOCS_URL = `${SITE_URL}/docs`; export const REPO_URL = "https://github.com/LycaonLLC/t4-code"; export const OMP_URL = "https://github.com/can1357/oh-my-pi"; export const OMP_RUNTIME_VERSION = "16.5.2"; -export const OMP_RUNTIME_COMMIT = "f9322817981e16bf3f1e3d77684f4269f026aa64"; -export const OMP_RUNTIME_TAG = "t4code-16.5.2-appserver-2"; +export const OMP_RUNTIME_COMMIT = "264958b23acac16baaf3bf0024129dc1a57f9d14"; +export const OMP_RUNTIME_TAG = "t4code-16.5.2-appserver-4"; export const OMP_RUNTIME_URL = `https://github.com/lyc-aon/oh-my-pi/tree/${OMP_RUNTIME_TAG}`; export const OMP_UPSTREAM_TAG = "v16.5.2"; export const OMP_UPSTREAM_COMMIT = "7d02778c60f4b5db60f84bedbca79d6e64cb91f5"; export const OMP_UPSTREAM_URL = `${OMP_URL}/tree/${OMP_UPSTREAM_TAG}`; export const APP_WIRE_VERSION = "0.5.5"; -export const RELEASE_TAG = "v0.1.15"; -export const RELEASE_VERSION = "0.1.15"; +export const RELEASE_TAG = "v0.1.16"; +export const RELEASE_VERSION = "0.1.16"; export const RELEASES_URL = `${REPO_URL}/releases/tag/${RELEASE_TAG}`; export type Platform = "android" | "linux" | "mac"; @@ -48,11 +48,11 @@ function asset( } export const RELEASE_ASSETS: readonly ReleaseAsset[] = [ - asset("android", "apk", "universal", "T4-Code-0.1.15-android.apk", "Android APK"), - asset("linux", "deb", "x86_64", "T4-Code-0.1.15-linux-amd64.deb", "Linux .deb"), - asset("linux", "appimage", "x86_64", "T4-Code-0.1.15-linux-x86_64.AppImage", "Linux AppImage"), - asset("mac", "dmg", "arm64", "T4-Code-0.1.15-mac-arm64.dmg", "macOS .dmg"), - asset("mac", "zip", "arm64", "T4-Code-0.1.15-mac-arm64.zip", "macOS .zip"), + asset("android", "apk", "universal", "T4-Code-0.1.16-android.apk", "Android APK"), + asset("linux", "deb", "x86_64", "T4-Code-0.1.16-linux-amd64.deb", "Linux .deb"), + asset("linux", "appimage", "x86_64", "T4-Code-0.1.16-linux-x86_64.AppImage", "Linux AppImage"), + asset("mac", "dmg", "arm64", "T4-Code-0.1.16-mac-arm64.dmg", "macOS .dmg"), + asset("mac", "zip", "arm64", "T4-Code-0.1.16-mac-arm64.zip", "macOS .zip"), ]; export function assetsFor(platform: Platform): readonly ReleaseAsset[] { diff --git a/apps/site/test/release.test.ts b/apps/site/test/release.test.ts index e37ad3c7..8259eab0 100644 --- a/apps/site/test/release.test.ts +++ b/apps/site/test/release.test.ts @@ -1,4 +1,4 @@ -// Release contract guard: exact v0.1.15 asset names and URLs, and the +// Release contract guard: exact v0.1.16 asset names and URLs, and the // platform-detection rule the hero download button relies on. import { describe, expect, it } from "vite-plus/test"; import { @@ -19,13 +19,13 @@ import { } from "../src/release.ts"; describe("release assets", () => { - it("carries the five contracted v0.1.15 filenames", () => { + it("carries the five contracted v0.1.16 filenames", () => { expect(RELEASE_ASSETS.map((a) => a.filename)).toEqual([ - "T4-Code-0.1.15-android.apk", - "T4-Code-0.1.15-linux-amd64.deb", - "T4-Code-0.1.15-linux-x86_64.AppImage", - "T4-Code-0.1.15-mac-arm64.dmg", - "T4-Code-0.1.15-mac-arm64.zip", + "T4-Code-0.1.16-android.apk", + "T4-Code-0.1.16-linux-amd64.deb", + "T4-Code-0.1.16-linux-x86_64.AppImage", + "T4-Code-0.1.16-mac-arm64.dmg", + "T4-Code-0.1.16-mac-arm64.zip", ]); }); @@ -37,8 +37,8 @@ describe("release assets", () => { it("targets the public LycaonLLC repo", () => { expect(REPO_URL).toBe("https://github.com/LycaonLLC/t4-code"); - expect(RELEASE_TAG).toBe("v0.1.15"); - expect(RELEASE_VERSION).toBe("0.1.15"); + expect(RELEASE_TAG).toBe("v0.1.16"); + expect(RELEASE_VERSION).toBe("0.1.16"); }); it("splits assets by platform with correct architectures", () => { @@ -59,10 +59,10 @@ describe("release assets", () => { describe("OMP integration contract", () => { it("pins the verified runtime tag, commit, and app-wire package", () => { - expect(OMP_RUNTIME_TAG).toBe("t4code-16.5.2-appserver-2"); - expect(OMP_RUNTIME_COMMIT).toBe("f9322817981e16bf3f1e3d77684f4269f026aa64"); + expect(OMP_RUNTIME_TAG).toBe("t4code-16.5.2-appserver-4"); + expect(OMP_RUNTIME_COMMIT).toBe("264958b23acac16baaf3bf0024129dc1a57f9d14"); expect(OMP_RUNTIME_URL).toBe( - "https://github.com/lyc-aon/oh-my-pi/tree/t4code-16.5.2-appserver-2", + "https://github.com/lyc-aon/oh-my-pi/tree/t4code-16.5.2-appserver-4", ); expect(OMP_UPSTREAM_TAG).toBe("v16.5.2"); expect(OMP_UPSTREAM_COMMIT).toBe("7d02778c60f4b5db60f84bedbca79d6e64cb91f5"); diff --git a/apps/web/package.json b/apps/web/package.json index e38243ba..a41526fe 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@t4-code/web", - "version": "0.1.15", + "version": "0.1.16", "private": true, "type": "module", "scripts": { diff --git a/apps/web/src/platform/browser-shell-port.ts b/apps/web/src/platform/browser-shell-port.ts index cd95507e..ee6d9b5f 100644 --- a/apps/web/src/platform/browser-shell-port.ts +++ b/apps/web/src/platform/browser-shell-port.ts @@ -279,7 +279,7 @@ export function createBrowserShellPort( }, client: { name: "T4 Code", - version: "0.1.15", + version: "0.1.16", build: mobilePlatform ?? "browser", platform: mobilePlatform ?? (platform === "darwin" ? "darwin" : "linux"), }, diff --git a/compat/omp-app-matrix.json b/compat/omp-app-matrix.json index ab49a7e1..6304e832 100644 --- a/compat/omp-app-matrix.json +++ b/compat/omp-app-matrix.json @@ -14,9 +14,9 @@ "package": "omp", "version": "16.5.2", "sourceRepository": "https://github.com/lyc-aon/oh-my-pi", - "sourceCommit": "f9322817981e16bf3f1e3d77684f4269f026aa64", - "sourceUrl": "https://github.com/lyc-aon/oh-my-pi/commit/f9322817981e16bf3f1e3d77684f4269f026aa64", - "sourceTag": "t4code-16.5.2-appserver-2", + "sourceCommit": "264958b23acac16baaf3bf0024129dc1a57f9d14", + "sourceUrl": "https://github.com/lyc-aon/oh-my-pi/commit/264958b23acac16baaf3bf0024129dc1a57f9d14", + "sourceTag": "t4code-16.5.2-appserver-4", "upstreamRepository": "https://github.com/can1357/oh-my-pi", "upstreamTag": "v16.5.2", "upstreamCommit": "7d02778c60f4b5db60f84bedbca79d6e64cb91f5", @@ -52,12 +52,14 @@ "structured-tool-result-details", "agent-transcript-streaming", "bounded-subagent-rpc-reads", - "child-transcript-image-reads" + "child-transcript-image-reads", + "clean-source-appserver-typecheck", + "required-appserver-runtime-release-gates" ], "upstreamTagContainsIntegrationPatches": false }, "desktop": { "package": "@t4-code/protocol", - "version": "0.1.15" + "version": "0.1.16" } } diff --git a/docs/CURRENT_RELEASE_NOTES.md b/docs/CURRENT_RELEASE_NOTES.md index e2d8aaf9..b8b6b222 100644 --- a/docs/CURRENT_RELEASE_NOTES.md +++ b/docs/CURRENT_RELEASE_NOTES.md @@ -1,6 +1,6 @@ -## Tool-aware transcripts and child agents +## Runtime release-gate hardening -T4 Code v0.1.15 gives known tools dedicated transcript views. Patch operations, task lists, child-agent work, file reads, shell commands, searches, and fetched sources show their useful arguments and structured results without exposing raw event payloads. +T4 Code v0.1.16 keeps the tool-aware transcript views and child-agent behavior shipped in v0.1.15. Patch operations, task lists, child-agent work, file reads, shell commands, searches, and fetched sources show their useful arguments and structured results without exposing raw event payloads. The Agents pane follows child-agent transcript events as they arrive and hydrates durable transcript records when opened. Child messages, tools, and images use the same rendering path as the main transcript. Subagent RPC reads have byte and record ceilings, so long-running agents remain responsive without unbounded transcript fetches. @@ -8,9 +8,9 @@ The runtime preserves sanitized structured tool-result details while omitting em ## Runtime compatibility -T4 Code v0.1.15 vendors app-wire 0.5.5 from integration commit [6a87fa64](https://github.com/lyc-aon/oh-my-pi/commit/6a87fa6407ebff20417b4d52885a6bb3091003ea), source tree `a2495fe8781c979184fe7fb9a6d37d8f33bad30f`. Image prompts activate only when the host advertises the additive image capability; the compatibility handshake keeps older appservers available. +T4 Code v0.1.16 vendors app-wire 0.5.5 from integration commit [6a87fa64](https://github.com/lyc-aon/oh-my-pi/commit/6a87fa6407ebff20417b4d52885a6bb3091003ea), source tree `a2495fe8781c979184fe7fb9a6d37d8f33bad30f`. Image prompts activate only when the host advertises the additive image capability; the compatibility handshake keeps older appservers available. -The matching OMP 16.5.2 runtime is built from [f9322817](https://github.com/lyc-aon/oh-my-pi/commit/f9322817981e16bf3f1e3d77684f4269f026aa64) and tagged [t4code-16.5.2-appserver-2](https://github.com/lyc-aon/oh-my-pi/tree/t4code-16.5.2-appserver-2). It carries forward T4's appserver, lifecycle, image, session-control, and atomic maintenance integration, then adds bounded child-agent transcript streaming and structured tool-result details. +The matching OMP 16.5.2 runtime is built from [264958b2](https://github.com/lyc-aon/oh-my-pi/commit/264958b23acac16baaf3bf0024129dc1a57f9d14) and tagged [t4code-16.5.2-appserver-4](https://github.com/lyc-aon/oh-my-pi/tree/t4code-16.5.2-appserver-4). The semantic runtime feature remains the appserver-2 implementation: bounded child-agent transcript streaming, structured tool-result details, bounded subagent reads, and verified child-transcript image reads. Appserver-4 fixes the clean-source TypeScript/build check and permanently adds the appserver type check plus full runtime tests to the gates that must pass before OMP release binaries publish. The integration is based on the official upstream [v16.5.2 tag](https://github.com/can1357/oh-my-pi/tree/v16.5.2), commit [7d02778c](https://github.com/can1357/oh-my-pi/commit/7d02778c60f4b5db60f84bedbca79d6e64cb91f5). Official upstream OMP v16.5.2 has no `appserver` command and cannot host T4 Code. diff --git a/e2e/site-mobile-docs.spec.ts b/e2e/site-mobile-docs.spec.ts index d63594c5..90151ced 100644 --- a/e2e/site-mobile-docs.spec.ts +++ b/e2e/site-mobile-docs.spec.ts @@ -129,7 +129,7 @@ test("offers the Android APK without hiding desktop downloads", async ({ page }) await expect(androidDownload).toBeVisible(); await expect(androidDownload).toHaveAttribute( "href", - "https://github.com/LycaonLLC/t4-code/releases/download/v0.1.15/T4-Code-0.1.15-android.apk", + "https://github.com/LycaonLLC/t4-code/releases/download/v0.1.16/T4-Code-0.1.16-android.apk", ); await expect(page.getByRole("link", { name: "Download for Linux" }).first()).toBeVisible(); await expect(page.getByRole("link", { name: "macOS build" }).first()).toBeVisible(); diff --git a/package.json b/package.json index f570b1f6..39549429 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@t4-code/root", - "version": "0.1.15", + "version": "0.1.16", "private": true, "type": "module", "scripts": { diff --git a/packages/client/package.json b/packages/client/package.json index 56b1b9e4..b1d849f8 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@t4-code/client", - "version": "0.1.15", + "version": "0.1.16", "private": true, "type": "module", "exports": { diff --git a/packages/client/src/omp-client-frames.ts b/packages/client/src/omp-client-frames.ts index 36df4ecd..7312fb2a 100644 --- a/packages/client/src/omp-client-frames.ts +++ b/packages/client/src/omp-client-frames.ts @@ -66,7 +66,7 @@ export function sendClientHello( v: PROTOCOL_VERSION, type: "hello", protocol: { min: PROTOCOL_VERSION, max: PROTOCOL_VERSION }, - client: options.client ?? { name: "t4-code", version: "0.1.15", build: "client", platform: "electron" }, + client: options.client ?? { name: "t4-code", version: "0.1.16", build: "client", platform: "electron" }, requestedFeatures: [...(options.requestedFeatures ?? ["resume"])], savedCursors, ...(options.capabilities === undefined ? {} : { capabilities: { client: [...options.capabilities] } }), diff --git a/packages/fixture-server/package.json b/packages/fixture-server/package.json index e06888c7..5408ab07 100644 --- a/packages/fixture-server/package.json +++ b/packages/fixture-server/package.json @@ -1,6 +1,6 @@ { "name": "@t4-code/fixture-server", - "version": "0.1.15", + "version": "0.1.16", "private": true, "type": "module", "exports": { diff --git a/packages/protocol/package.json b/packages/protocol/package.json index 0dc4c13d..61288e95 100644 --- a/packages/protocol/package.json +++ b/packages/protocol/package.json @@ -1,6 +1,6 @@ { "name": "@t4-code/protocol", - "version": "0.1.15", + "version": "0.1.16", "private": true, "type": "module", "exports": { diff --git a/packages/remote/package.json b/packages/remote/package.json index 0129108c..ad145fda 100644 --- a/packages/remote/package.json +++ b/packages/remote/package.json @@ -1,6 +1,6 @@ { "name": "@t4-code/remote", - "version": "0.1.15", + "version": "0.1.16", "private": true, "type": "module", "exports": { diff --git a/packages/service-manager/package.json b/packages/service-manager/package.json index a1a54a2a..edb47bec 100644 --- a/packages/service-manager/package.json +++ b/packages/service-manager/package.json @@ -1,6 +1,6 @@ { "name": "@t4-code/service-manager", - "version": "0.1.15", + "version": "0.1.16", "private": true, "type": "module", "exports": { diff --git a/packages/ui/package.json b/packages/ui/package.json index 1a544306..018441c1 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@t4-code/ui", - "version": "0.1.15", + "version": "0.1.16", "private": true, "type": "module", "exports": { diff --git a/scripts/check-release-consistency.test.mjs b/scripts/check-release-consistency.test.mjs index 92daeb75..0e8eaf26 100644 --- a/scripts/check-release-consistency.test.mjs +++ b/scripts/check-release-consistency.test.mjs @@ -17,28 +17,28 @@ function changed(path, replace) { } test("current source tree has one consistent release version", () => { - assert.deepEqual(collectReleaseConsistencyErrors(files, "v0.1.15"), []); + assert.deepEqual(collectReleaseConsistencyErrors(files, "v0.1.16"), []); }); test("rejects a tag that differs from the package version", () => { assert.ok( collectReleaseConsistencyErrors(files, "v9.9.9").some((error) => - error.includes("release tag v9.9.9 does not match v0.1.15"), + error.includes("release tag v9.9.9 does not match v0.1.16"), ), ); }); test("rejects workspace, site, README, and runtime version drift", () => { const cases = [ - ["apps/web/package.json", (text) => text.replace('"version": "0.1.15"', '"version": "0.1.3"')], + ["apps/web/package.json", (text) => text.replace('"version": "0.1.16"', '"version": "0.1.3"')], [ "apps/site/src/release.ts", - (text) => text.replace('RELEASE_TAG = "v0.1.15"', 'RELEASE_TAG = "v0.1.3"'), + (text) => text.replace('RELEASE_TAG = "v0.1.16"', 'RELEASE_TAG = "v0.1.3"'), ], - ["README.md", (text) => text.replace("Download v0.1.15", "Download v0.1.3")], + ["README.md", (text) => text.replace("Download v0.1.16", "Download v0.1.3")], [ "apps/desktop/src/target-manager.ts", - (text) => text.replace('version: "0.1.15"', 'version: "0.1.3"'), + (text) => text.replace('version: "0.1.16"', 'version: "0.1.3"'), ], [ "apps/site/src/docs/content.ts", @@ -105,10 +105,10 @@ test("rejects drift in verified OMP runtime provenance", () => { const cases = [ (text) => text.replace( - "f9322817981e16bf3f1e3d77684f4269f026aa64", + "264958b23acac16baaf3bf0024129dc1a57f9d14", "0000000000000000000000000000000000000000", ), - (text) => text.replace('"sourceTag": "t4code-16.5.2-appserver-2"', '"sourceTag": "wrong-tag"'), + (text) => text.replace('"sourceTag": "t4code-16.5.2-appserver-4"', '"sourceTag": "wrong-tag"'), (text) => text.replace( '"upstreamCommit": "7d02778c60f4b5db60f84bedbca79d6e64cb91f5"', @@ -173,7 +173,7 @@ test("rejects stale README release URLs while allowing historical prose", () => const staleLink = changed("README.md", (text) => `${text}\n[Old release](${oldReleaseUrl})\n`); assert.ok( collectReleaseConsistencyErrors(staleLink).some((error) => - error.includes("release URL for v0.1.3; expected v0.1.15"), + error.includes("release URL for v0.1.3; expected v0.1.16"), ), ); assert.deepEqual(collectReleaseConsistencyErrors(files), []); diff --git a/scripts/inspect-macos-dmg.test.mjs b/scripts/inspect-macos-dmg.test.mjs index 5857f3f0..29721d5d 100644 --- a/scripts/inspect-macos-dmg.test.mjs +++ b/scripts/inspect-macos-dmg.test.mjs @@ -5,7 +5,7 @@ import { resolve } from "node:path"; import { findMountedApp, inspectMacosDmg } from "./inspect-macos-dmg.mjs"; -const dmgPath = "/tmp/T4-Code-0.1.15-mac-arm64.dmg"; +const dmgPath = "/tmp/T4-Code-0.1.16-mac-arm64.dmg"; const mountPoint = "/tmp/t4-code-dmg-test"; function directory(name) { diff --git a/scripts/packaging.test.mjs b/scripts/packaging.test.mjs index 445b9cf9..e5a3de0e 100644 --- a/scripts/packaging.test.mjs +++ b/scripts/packaging.test.mjs @@ -28,7 +28,7 @@ const androidIdentity = JSON.parse(readFileSync(resolve(repoRoot, ".github/andro const productionCertificate = "fa58f53c953a078d8db2b633ee8c226cfd2ad3f7220cd55dd03a2e195a81b0ac"; function androidReleaseFixture(overrides = {}) { - const packageVersion = overrides.packageVersion ?? "0.1.15"; + const packageVersion = overrides.packageVersion ?? "0.1.16"; const versionCode = deriveAndroidVersionCode(packageVersion); const contract = structuredClone(androidIdentity); Object.assign(contract, overrides.contract); @@ -90,9 +90,9 @@ test("Android release identity is public, pinned, and wired into the release wor test("Android versionCode is derived from the package version without a release-specific constant", () => { assert.equal(deriveAndroidVersionCode("0.1.13"), 10_013); - assert.equal(deriveAndroidVersionCode("0.1.15"), 10_015); + assert.equal(deriveAndroidVersionCode("0.1.16"), 10_016); assert.equal(deriveAndroidVersionCode("1.2.3456"), 1_023_456); - assert.throws(() => deriveAndroidVersionCode("0.1.15-beta.1"), /numeric major\.minor\.patch/u); + assert.throws(() => deriveAndroidVersionCode("0.1.16-beta.1"), /numeric major\.minor\.patch/u); assert.throws(() => deriveAndroidVersionCode("0.100.0"), /minor version must be at most 99/u); assert.throws(() => deriveAndroidVersionCode("0.1.10000"), /patch version must be at most 9999/u); }); @@ -100,12 +100,12 @@ test("Android versionCode is derived from the package version without a release- test("Android artifact parsers preserve exact package, SDK, split, and certificate identity", () => { assert.deepEqual( parseAaptBadging( - "package: name='com.lycaonsolutions.t4code' versionCode='10015' versionName='0.1.15'\nsdkVersion:'24'\ntargetSdkVersion:'36'\n", + "package: name='com.lycaonsolutions.t4code' versionCode='10016' versionName='0.1.16'\nsdkVersion:'24'\ntargetSdkVersion:'36'\n", ), { applicationId: "com.lycaonsolutions.t4code", - versionCode: 10_015, - versionName: "0.1.15", + versionCode: 10_016, + versionName: "0.1.16", minSdkVersion: 24, targetSdkVersion: 36, splitName: null, @@ -127,8 +127,8 @@ test("Android artifact parsers preserve exact package, SDK, split, and certifica test("Android release inspector accepts the exact production universal APK contract", () => { assert.deepEqual(validateAndroidRelease(androidReleaseFixture()), { applicationId: "com.lycaonsolutions.t4code", - versionName: "0.1.15", - versionCode: 10_015, + versionName: "0.1.16", + versionCode: 10_016, minSdkVersion: 24, targetSdkVersion: 36, signingCertificateSha256: productionCertificate, @@ -140,42 +140,42 @@ test("Android release inspector fails closed on identity, SDK, split, and signer [ "application id", { - badgingOutput: "package: name='example.wrong' versionCode='10015' versionName='0.1.15'\nsdkVersion:'24'\ntargetSdkVersion:'36'\n", + badgingOutput: "package: name='example.wrong' versionCode='10016' versionName='0.1.16'\nsdkVersion:'24'\ntargetSdkVersion:'36'\n", }, /applicationId example\.wrong/u, ], [ "version name", { - badgingOutput: "package: name='com.lycaonsolutions.t4code' versionCode='10015' versionName='0.1.16'\nsdkVersion:'24'\ntargetSdkVersion:'36'\n", + badgingOutput: "package: name='com.lycaonsolutions.t4code' versionCode='10016' versionName='0.1.17'\nsdkVersion:'24'\ntargetSdkVersion:'36'\n", }, - /versionName 0\.1\.16/u, + /versionName 0\.1\.17/u, ], [ "version code", { - badgingOutput: "package: name='com.lycaonsolutions.t4code' versionCode='10014' versionName='0.1.15'\nsdkVersion:'24'\ntargetSdkVersion:'36'\n", + badgingOutput: "package: name='com.lycaonsolutions.t4code' versionCode='10015' versionName='0.1.16'\nsdkVersion:'24'\ntargetSdkVersion:'36'\n", }, - /versionCode 10014/u, + /versionCode 10015/u, ], [ "minimum sdk", { - badgingOutput: "package: name='com.lycaonsolutions.t4code' versionCode='10015' versionName='0.1.15'\nsdkVersion:'23'\ntargetSdkVersion:'36'\n", + badgingOutput: "package: name='com.lycaonsolutions.t4code' versionCode='10016' versionName='0.1.16'\nsdkVersion:'23'\ntargetSdkVersion:'36'\n", }, /minSdkVersion 23/u, ], [ "target sdk", { - badgingOutput: "package: name='com.lycaonsolutions.t4code' versionCode='10015' versionName='0.1.15'\nsdkVersion:'24'\ntargetSdkVersion:'35'\n", + badgingOutput: "package: name='com.lycaonsolutions.t4code' versionCode='10016' versionName='0.1.16'\nsdkVersion:'24'\ntargetSdkVersion:'35'\n", }, /targetSdkVersion 35/u, ], [ "split package", { - badgingOutput: "package: name='com.lycaonsolutions.t4code' versionCode='10015' versionName='0.1.15' split='config.arm64_v8a'\nsdkVersion:'24'\ntargetSdkVersion:'36'\n", + badgingOutput: "package: name='com.lycaonsolutions.t4code' versionCode='10016' versionName='0.1.16' split='config.arm64_v8a'\nsdkVersion:'24'\ntargetSdkVersion:'36'\n", }, /standalone/u, ], @@ -191,8 +191,8 @@ test("Android release inspector fails closed on identity, SDK, split, and signer { type: "SINGLE", filters: [{ filterType: "ABI", value: "arm64-v8a" }], - versionCode: 10_015, - versionName: "0.1.15", + versionCode: 10_016, + versionName: "0.1.16", outputFile: "app-release.apk", }, ], diff --git a/scripts/wait-for-release-assets.test.mjs b/scripts/wait-for-release-assets.test.mjs index b71b8bb2..6f444d9f 100644 --- a/scripts/wait-for-release-assets.test.mjs +++ b/scripts/wait-for-release-assets.test.mjs @@ -7,13 +7,13 @@ const quiet = { log() {} }; test("builds the five package URLs and checksum URL for one release tag", () => { assert.deepEqual( - releaseAssetUrls("0.1.15").map(({ filename }) => filename), + releaseAssetUrls("0.1.16").map(({ filename }) => filename), [ - "T4-Code-0.1.15-android.apk", - "T4-Code-0.1.15-linux-amd64.deb", - "T4-Code-0.1.15-linux-x86_64.AppImage", - "T4-Code-0.1.15-mac-arm64.dmg", - "T4-Code-0.1.15-mac-arm64.zip", + "T4-Code-0.1.16-android.apk", + "T4-Code-0.1.16-linux-amd64.deb", + "T4-Code-0.1.16-linux-x86_64.AppImage", + "T4-Code-0.1.16-mac-arm64.dmg", + "T4-Code-0.1.16-mac-arm64.zip", "SHA256SUMS.txt", ], ); @@ -21,7 +21,7 @@ test("builds the five package URLs and checksum URL for one release tag", () => test("passes only when every public release file returns HTTP 200", async () => { const result = await waitForReleaseAssets({ - version: "0.1.15", + version: "0.1.16", fetchImpl: async () => ({ status: 200 }), logger: quiet, }); @@ -33,7 +33,7 @@ test("retries unavailable files and stays inside the configured timeout", async let currentTime = 0; let calls = 0; const result = await waitForReleaseAssets({ - version: "0.1.15", + version: "0.1.16", timeoutMs: 100, intervalMs: 20, requestTimeoutMs: 5, @@ -50,7 +50,7 @@ test("fails closed at the timeout and reports filenames without response content let currentTime = 0; await assert.rejects( waitForReleaseAssets({ - version: "0.1.15", + version: "0.1.16", timeoutMs: 40, intervalMs: 25, requestTimeoutMs: 5,