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
20 changes: 19 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,25 @@ jobs:
fi
fi

bun run dist:desktop:artifact -- "${args[@]}"
build_desktop_artifact() {
bun run dist:desktop:artifact -- "${args[@]}"
}

if [[ "${{ matrix.platform }}" == "mac" ]]; then
for attempt in 1 2; do
if build_desktop_artifact; then
break
fi
if [[ "$attempt" -eq 1 ]]; then
echo "macOS desktop packaging failed once; retrying after a short delay..." >&2
sleep 30
continue
fi
exit 1
done
else
build_desktop_artifact
fi

- name: Validate packaged artifact outputs
shell: bash
Expand Down
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.26.4] - 2026-04-22

See [docs/releases/v0.26.4.md](docs/releases/v0.26.4.md) for full notes and [docs/releases/v0.26.4/assets.md](docs/releases/v0.26.4/assets.md) for release asset inventory.

### Added

- Add out-of-memory session recovery.

### Changed

- Bundle diffs into the server cli.
- Inline diff parsing for cli release.

### Fixed

- Publish cli from cjs bin.
- Make npm publish rerun-safe.
- Verify published cli with okcode bin.
- Verify published cli with temp install.

## [0.26.3] - 2026-04-22

See [docs/releases/v0.26.3.md](docs/releases/v0.26.3.md) for full notes and [docs/releases/v0.26.3/assets.md](docs/releases/v0.26.3/assets.md) for release asset inventory.
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@okcode/desktop",
"version": "0.26.3",
"version": "0.26.4",
"private": true,
"main": "dist-electron/main.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "0.26.3"
versionName "0.26.4"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
Expand Down
4 changes: 2 additions & 2 deletions apps/mobile/ios/App/App.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.26.3;
MARKETING_VERSION = 0.26.4;
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
PRODUCT_BUNDLE_IDENTIFIER = com.openknots.okcode.mobile;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand All @@ -331,7 +331,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.26.3;
MARKETING_VERSION = 0.26.4;
PRODUCT_BUNDLE_IDENTIFIER = com.openknots.okcode.mobile;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@okcode/mobile",
"version": "0.26.3",
"version": "0.26.4",
"private": true,
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion apps/server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "okcodes",
"version": "0.26.3",
"version": "0.26.4",
"license": "MIT",
"repository": {
"type": "git",
Expand Down
66 changes: 56 additions & 10 deletions apps/server/src/checkpointing/Diffs.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
import { parsePatchFiles } from "@pierre/diffs";

export interface TurnDiffFileSummary {
readonly path: string;
readonly additions: number;
readonly deletions: number;
}

interface MutableTurnDiffFileSummary {
path: string;
additions: number;
deletions: number;
}

function normalizeDiffPath(path: string): string {
return path.replace(/^a\//, "").replace(/^b\//, "");
}

function createFileSummary(path: string): MutableTurnDiffFileSummary {
return { path, additions: 0, deletions: 0 };
}

export function parseTurnDiffFilesFromUnifiedDiff(
diff: string,
): ReadonlyArray<TurnDiffFileSummary> {
Expand All @@ -14,14 +26,48 @@ export function parseTurnDiffFilesFromUnifiedDiff(
return [];
}

const parsedPatches = parsePatchFiles(normalized);
const files = parsedPatches.flatMap((patch) =>
patch.files.map((file) => ({
path: file.name,
additions: file.hunks.reduce((total, hunk) => total + hunk.additionLines, 0),
deletions: file.hunks.reduce((total, hunk) => total + hunk.deletionLines, 0),
})),
);
const files: MutableTurnDiffFileSummary[] = [];
let currentFile: MutableTurnDiffFileSummary | null = null;
let inHunk = false;

for (const line of normalized.split("\n")) {
if (line.startsWith("diff --git ")) {
if (currentFile) files.push(currentFile);

const match = /^diff --git a\/(.+?) b\/(.+)$/.exec(line);
currentFile = createFileSummary(normalizeDiffPath(match?.[2] ?? match?.[1] ?? line));
inHunk = false;
continue;
}

if (!currentFile) {
continue;
}

if (line.startsWith("@@")) {
inHunk = true;
continue;
}

if (!inHunk) {
continue;
}

if (line.startsWith("+++ ") || line.startsWith("--- ")) {
continue;
}

if (line.startsWith("+")) {
currentFile.additions += 1;
continue;
}

if (line.startsWith("-")) {
currentFile.deletions += 1;
}
}

if (currentFile) files.push(currentFile);

return files.toSorted((left, right) => left.path.localeCompare(right.path));
}
2 changes: 1 addition & 1 deletion apps/server/tsdown.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default defineConfig({
outDir: "dist",
sourcemap: true,
clean: true,
noExternal: (id) => id.startsWith("@okcode/"),
noExternal: (id) => id.startsWith("@okcode/") || id === "@pierre/diffs",
inlineOnly: false,
banner: {
js: "#!/usr/bin/env node\n",
Expand Down
2 changes: 1 addition & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@okcode/web",
"version": "0.26.3",
"version": "0.26.4",
"private": true,
"type": "module",
"scripts": {
Expand Down
11 changes: 11 additions & 0 deletions apps/web/src/components/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3895,6 +3895,17 @@ export default function ChatView({
});
};

const onRecoverFromOutOfMemory = async () => {
const api = readNativeApi();
if (!api || !activeThread || isRemoteActionBlocked) return;
await api.orchestration.dispatchCommand({
type: "thread.session.stop",
commandId: newCommandId(),
threadId: activeThread.id,
createdAt: new Date().toISOString(),
});
};

const onClearQueue = useCallback(() => {
setOptimisticUserMessages((existing) => {
for (const msg of existing) {
Expand Down
1 change: 1 addition & 0 deletions docs/releases/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Use this directory for versioned release notes and asset manifests only:

| Version | Summary | Assets |
| -------------------- | --------------------------------------------------------------------------------------------------------- | ----------------------------- |
| [0.26.4](v0.26.4.md) | Out-of-memory session recovery and CLI release hardening | [manifest](v0.26.4/assets.md) |
| [0.26.3](v0.26.3.md) | Release with 2 new feature(s) | [manifest](v0.26.3/assets.md) |
| [0.26.2](v0.26.2.md) | Release with 1 new feature(s), 4 fix(es), 3 improvement(s) | [manifest](v0.26.2/assets.md) |
| [0.26.0](v0.26.0.md) | File-content search, desktop terminal docking, transport sna | [manifest](v0.26.0/assets.md) |
Expand Down
38 changes: 38 additions & 0 deletions docs/releases/v0.26.4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# OK Code v0.26.4

**Date:** 2026-04-22
**Tag:** [`v0.26.4`](https://github.com/OpenKnots/okcode/releases/tag/v0.26.4)

## Summary

Re-cut release after `v0.26.3` was already present on npm; ships the same branch state with out-of-memory session recovery and CLI release hardening.

## Highlights

- **Add out-of-memory session recovery.**
- **Bundle diffs into the server cli.**
- **Inline diff parsing for cli release.**
- **Publish cli from cjs bin.**
- **Make npm publish rerun-safe.**
- **Verify published cli with okcode bin.**
- **Verify published cli with temp install.**

## Breaking changes

- None.

## Upgrade and install

- **CLI:** `npm install -g okcodes@0.26.4` once the desktop/CLI release workflow finishes.
- **Desktop:** Download from [GitHub Releases](https://github.com/OpenKnots/okcode/releases/tag/v0.26.4). Filenames are listed in [assets.md](v0.26.4/assets.md).
- **iOS:** Available via TestFlight after the separate Release iOS workflow is dispatched for this tag.

## Known limitations

OK Code remains early work in progress. Expect rough edges around session recovery, streaming edge cases, and platform-specific desktop behavior. Report issues on GitHub.

## Release operations

- Review the [asset manifest](v0.26.4/assets.md) to confirm every expected GitHub Release attachment is present.
- Use the [rollout checklist](v0.26.4/rollout-checklist.md) to walk the desktop/CLI release plus the separate iOS TestFlight dispatch through post-release verification.
- Use the [soak test plan](v0.26.4/soak-test-plan.md) to validate the highest-risk surfaces after the tag is live.
57 changes: 57 additions & 0 deletions docs/releases/v0.26.4/assets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# v0.26.4 — Release assets (manifest)

Binaries are **not** stored in this git repository; they are attached to the [GitHub Release for `v0.26.4`](https://github.com/OpenKnots/okcode/releases/tag/v0.26.4) by the [Release workflow](../../.github/workflows/release.yml).

The GitHub Release also includes **documentation attachments** (same content as in-repo, stable filenames for download):

| File | Source in repo |
| --------------------------- | ------------------------------------- |
| `okcode-CHANGELOG.md` | [CHANGELOG.md](../../../CHANGELOG.md) |
| `okcode-RELEASE-NOTES.md` | [v0.26.4.md](../v0.26.4.md) |
| `okcode-ASSETS-MANIFEST.md` | This file |

After the workflow completes, expect **installer and updater** artifacts similar to the following (exact names may include the product name `OK Code` and version `0.26.4`).

## Desktop installers and payloads

| Platform | Kind | Typical pattern |
| ------------------- | -------------- | --------------- |
| macOS Apple Silicon | DMG (signed) | `*.dmg` (arm64) |
| macOS Intel | DMG (signed) | `*.dmg` (x64) |
| macOS | ZIP (updater) | `*.zip` |
| Linux x64 | AppImage | `*.AppImage` |
| Windows x64 | NSIS installer | `*.exe` |

### macOS code signing and notarization

All macOS DMG and ZIP payloads are **code-signed** with an Apple Developer ID certificate and **notarized** via the Apple notarization service. Gatekeeper will verify the signature on first launch. The hardened runtime is enabled with entitlements defined in `apps/desktop/resources/entitlements.mac.plist`.

## Electron updater metadata

| File | Purpose |
| ------------------ | --------------------------------------------------------- |
| `latest-mac.yml` | macOS update manifest (merged from per-arch builds in CI) |
| `latest-linux.yml` | Linux update manifest |
| `latest.yml` | Windows update manifest |
| `*.blockmap` | Differential download block maps |

## iOS (TestFlight)

The iOS build is uploaded directly to App Store Connect / TestFlight by the separately dispatched [Release iOS workflow](../../.github/workflows/release-ios.yml). No IPA artifact is attached to the GitHub Release.

| Detail | Value |
| ----------------- | ------------------------------------------ |
| Bundle ID | `com.openknots.okcode.mobile` |
| Marketing version | `0.26.4` |
| Build number | Set from `GITHUB_RUN_NUMBER` at build time |

## Checksums

SHA-256 checksums are not committed here; verify downloads via GitHub's release UI or `gh release download` if you use the GitHub CLI.

## Operational references

| File | Purpose |
| -------------------------------------------- | ----------------------------------------------------------------- |
| [rollout-checklist.md](rollout-checklist.md) | Step-by-step release playbook from preflight through post-release |
| [soak-test-plan.md](soak-test-plan.md) | Structured release validation for the highest-risk surfaces |
67 changes: 67 additions & 0 deletions docs/releases/v0.26.4/rollout-checklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# v0.26.4 Rollout Checklist

Step-by-step playbook for the v0.26.4 release. Each phase must complete before advancing.

## Phase 0: Pre-flight

- [ ] Verify all release package versions are `0.26.4`:
- `apps/server/package.json`
- `apps/desktop/package.json`
- `apps/web/package.json`
- `apps/mobile/package.json`
- `packages/contracts/package.json`
- [ ] Verify Android `versionName` and iOS `MARKETING_VERSION` both match `0.26.4`.
- [ ] Confirm `CHANGELOG.md` has `## [0.26.4] - 2026-04-22`.
- [ ] Confirm `docs/releases/v0.26.4.md` exists with Summary, Highlights, Upgrade and install, and Release operations sections.
- [ ] Confirm `docs/releases/v0.26.4/assets.md` exists and lists every expected attachment class.
- [ ] Confirm `docs/releases/v0.26.4/rollout-checklist.md` and `docs/releases/v0.26.4/soak-test-plan.md` exist.
- [ ] Confirm `docs/releases/README.md` includes the v0.26.4 row.
- [ ] Run `bun run release:validate 0.26.4`.
- [ ] Confirm the working tree is clean.
- [ ] Confirm you are on `main`.

### Quality gates

- [ ] `bun run fmt:check`
- [ ] `bun run lint`
- [ ] `bun run typecheck`
- [ ] `bun run test`
- [ ] `bun run --cwd apps/web test:browser`
- [ ] `bun run test:desktop-smoke`
- [ ] `bun run release:smoke`

## Phase 1: Publish

- [ ] Push the release-prep commit to `main`.
- [ ] Create and push tag `v0.26.4`.
- [ ] Verify the coordinated `release.yml` workflow starts.
- [ ] Trigger `release-ios.yml` manually for `v0.26.4` (or the matching release ref if the tag is unavailable).
- [ ] Monitor `release.yml` through Preflight, Desktop builds, Publish CLI, Publish GitHub Release, and Finalize release.
- [ ] Monitor `release-ios.yml` through Preflight, iOS signing preflight, and iOS TestFlight.

### Asset verification

- [ ] GitHub Release body matches `docs/releases/v0.26.4.md`.
- [ ] `okcode-CHANGELOG.md` is attached.
- [ ] `okcode-RELEASE-NOTES.md` is attached.
- [ ] `okcode-ASSETS-MANIFEST.md` is attached.
- [ ] macOS release artifacts are attached: DMG, ZIP, updater manifest, and blockmaps.
- [ ] Linux release artifacts are attached: AppImage and updater manifest if generated.
- [ ] Windows release artifacts are attached: installer, updater manifest, and blockmaps.
- [ ] If the Intel compatibility workflow is run, confirm the x64 macOS DMG is attached separately.

## Phase 2: Post-release verification

- [ ] `npm exec --yes --package okcodes@0.26.4 -- okcode --version` returns `0.26.4`.
- [ ] macOS installer launches and passes Gatekeeper.
- [ ] Linux AppImage launches.
- [ ] Windows installer installs and launches.
- [ ] Desktop auto-update metadata is present for supported platforms.
- [ ] If iOS signing was enabled, confirm the new TestFlight build appears.
- [ ] Confirm the finalize job did not need to push another version-alignment commit, or review its no-op output if versions were already aligned before tagging.

## Phase 3: Follow-through

- [ ] Trigger the Intel compatibility workflow if macOS x64 artifacts are required for this train.
- [ ] Update external release references or announcements.
- [ ] Monitor reports for regressions in provider onboarding, auth flows, release packaging, and cross-platform install/update behavior.
Loading
Loading