Skip to content
Closed
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
File renamed without changes
2 changes: 1 addition & 1 deletion apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@
"vitest": "catalog:",
"wait-on": "^8.0.2"
},
"productName": "CUT3"
"productName": "Rowl"
}
Binary file modified apps/desktop/resources/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 18 additions & 18 deletions apps/desktop/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ const UPDATE_STATE_CHANNEL = "desktop:update-state";
const UPDATE_GET_STATE_CHANNEL = "desktop:update-get-state";
const UPDATE_DOWNLOAD_CHANNEL = "desktop:update-download";
const UPDATE_INSTALL_CHANNEL = "desktop:update-install";
const DESKTOP_SCHEME = "cut3";
const DESKTOP_SCHEME = "rowl";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep desktop URL scheme aligned with WS origin allowlist

Changing the desktop protocol scheme to rowl means packaged renderer requests will originate from rowl://app, but the server still only whitelists cut3://app in apps/server/src/networking.ts (DESKTOP_APP_ORIGIN). In desktop mode with auth enabled, websocket upgrades that include Origin: rowl://app will be rejected as a forbidden origin, which can prevent the desktop client from connecting to the backend at all. Update the server allowlist in the same change (or temporarily accept both origins).

Useful? React with 👍 / 👎.

const ROOT_DIR = Path.resolve(__dirname, "../../..");
const isDevelopment = Boolean(process.env.VITE_DEV_SERVER_URL);
const appReleaseBranding = resolveAppReleaseBranding({
version: app.getVersion(),
isDevelopment,
});
const STATE_DIR =
process.env.CUT3_STATE_DIR?.trim() ||
process.env.ROWL_STATE_DIR?.trim() ||
Path.join(OS.homedir(), ".t3", appReleaseBranding.stateDirName);
const APP_DISPLAY_NAME = appReleaseBranding.displayName;
const APP_USER_MODEL_ID = appReleaseBranding.appId;
Expand Down Expand Up @@ -530,8 +530,8 @@ function resolveEmbeddedCommitHash(): string | null {

try {
const raw = FS.readFileSync(packageJsonPath, "utf8");
const parsed = JSON.parse(raw) as { cut3CommitHash?: unknown };
return normalizeCommitHash(parsed.cut3CommitHash);
const parsed = JSON.parse(raw) as { rowlCommitHash?: unknown };
return normalizeCommitHash(parsed.rowlCommitHash);
} catch {
return null;
}
Expand All @@ -542,7 +542,7 @@ function resolveAboutCommitHash(): string | null {
return aboutCommitHashCache;
}

const envCommitHash = normalizeCommitHash(process.env.CUT3_COMMIT_HASH);
const envCommitHash = normalizeCommitHash(process.env.ROWL_COMMIT_HASH);
if (envCommitHash) {
aboutCommitHashCache = envCommitHash;
return aboutCommitHashCache;
Expand All @@ -564,7 +564,7 @@ function resolveBackendEntry(): string {
}

function resolveBackendCwd(): string {
const override = process.env.CUT3_BACKEND_CWD?.trim();
const override = process.env.ROWL_BACKEND_CWD?.trim();
if (override) {
return override;
}
Expand Down Expand Up @@ -630,7 +630,7 @@ function handleFatalStartupError(stage: string, error: unknown): void {
console.error(`[desktop] fatal startup error (${stage})`, error);
if (!isQuitting) {
isQuitting = true;
dialog.showErrorBox("CUT3 failed to start", `Stage: ${stage}\n${message}${detail}`);
dialog.showErrorBox("Rowl failed to start", `Stage: ${stage}\n${message}${detail}`);
}
stopBackend();
restoreStdIoCapture?.();
Expand All @@ -651,7 +651,7 @@ function updateBackendWsUrl(port: number): void {
port,
authToken: backendAuthToken,
});
process.env.CUT3_DESKTOP_WS_URL = backendWsUrl;
process.env.ROWL_DESKTOP_WS_URL = backendWsUrl;
writeDesktopLogHeader(`backend websocket url updated port=${port}`);
broadcastBackendWsUrl();
}
Expand Down Expand Up @@ -747,7 +747,7 @@ function handleCheckForUpdatesMenuClick(): void {
isPackaged: app.isPackaged,
platform: process.platform,
appImage: process.env.APPIMAGE,
disabledByEnv: process.env.CUT3_DISABLE_AUTO_UPDATE === "1",
disabledByEnv: process.env.ROWL_DISABLE_AUTO_UPDATE === "1",
});
if (disabledReason) {
console.info("[desktop-updater] Manual update check requested, but updates are disabled.");
Expand All @@ -774,7 +774,7 @@ async function checkForUpdatesFromMenu(): Promise<void> {
void dialog.showMessageBox({
type: "info",
title: "You're up to date!",
message: `CUT3 ${updateState.currentVersion} is currently the newest version available.`,
message: `Rowl ${updateState.currentVersion} is currently the newest version available.`,
buttons: ["OK"],
});
} else if (updateState.status === "error") {
Expand Down Expand Up @@ -999,7 +999,7 @@ function shouldEnableAutoUpdates(): boolean {
isPackaged: app.isPackaged,
platform: process.platform,
appImage: process.env.APPIMAGE,
disabledByEnv: process.env.CUT3_DISABLE_AUTO_UPDATE === "1",
disabledByEnv: process.env.ROWL_DISABLE_AUTO_UPDATE === "1",
}) === null
);
}
Expand Down Expand Up @@ -1084,7 +1084,7 @@ function configureAutoUpdater(): void {
updaterConfigured = true;

const githubToken =
process.env.CUT3_DESKTOP_UPDATE_GITHUB_TOKEN?.trim() || process.env.GH_TOKEN?.trim() || "";
process.env.ROWL_DESKTOP_UPDATE_GITHUB_TOKEN?.trim() || process.env.GH_TOKEN?.trim() || "";
if (githubToken) {
// When a token is provided, re-configure the feed with `private: true` so
// electron-updater uses the GitHub API (api.github.com) instead of the
Expand Down Expand Up @@ -1187,11 +1187,11 @@ function configureAutoUpdater(): void {
function backendEnv(): NodeJS.ProcessEnv {
return {
...process.env,
CUT3_MODE: "desktop",
CUT3_NO_BROWSER: "1",
CUT3_PORT: "0",
CUT3_STATE_DIR: STATE_DIR,
CUT3_AUTH_TOKEN: backendAuthToken,
ROWL_MODE: "desktop",
ROWL_NO_BROWSER: "1",
ROWL_PORT: "0",
ROWL_STATE_DIR: STATE_DIR,
ROWL_AUTH_TOKEN: backendAuthToken,
};
}

Expand Down Expand Up @@ -1598,7 +1598,7 @@ function createWindow(): BrowserWindow {
contextIsolation: true,
nodeIntegration: false,
sandbox: true,
additionalArguments: backendWsUrl ? [`--cut3-desktop-ws-url=${backendWsUrl}`] : [],
additionalArguments: backendWsUrl ? [`--rowl-desktop-ws-url=${backendWsUrl}`] : [],
},
});

Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const UPDATE_STATE_CHANNEL = "desktop:update-state";
const UPDATE_GET_STATE_CHANNEL = "desktop:update-get-state";
const UPDATE_DOWNLOAD_CHANNEL = "desktop:update-download";
const UPDATE_INSTALL_CHANNEL = "desktop:update-install";
let wsUrl = process.env.CUT3_DESKTOP_WS_URL ?? null;
let wsUrl = process.env.ROWL_DESKTOP_WS_URL ?? null;
wsUrl = resolveInitialDesktopWsUrl({ envValue: wsUrl, argv: process.argv });

ipcRenderer.on(BACKEND_WS_URL_UPDATED_CHANNEL, (_event, nextUrl: unknown) => {
Expand Down
4 changes: 2 additions & 2 deletions apps/desktop/src/preloadWsUrl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe("resolveInitialDesktopWsUrl", () => {
expect(
resolveInitialDesktopWsUrl({
envValue: "ws://127.0.0.1:3773/?token=env-token",
argv: ["electron", "app.js", "--cut3-desktop-ws-url=ws://127.0.0.1:4000"],
argv: ["electron", "app.js", "--rowl-desktop-ws-url=ws://127.0.0.1:4000"],
}),
).toBe("ws://127.0.0.1:3773/?token=env-token");
});
Expand All @@ -16,7 +16,7 @@ describe("resolveInitialDesktopWsUrl", () => {
expect(
resolveInitialDesktopWsUrl({
envValue: undefined,
argv: ["electron", "app.js", "--cut3-desktop-ws-url=ws://127.0.0.1:4000/?token=test"],
argv: ["electron", "app.js", "--rowl-desktop-ws-url=ws://127.0.0.1:4000/?token=test"],
}),
).toBe("ws://127.0.0.1:4000/?token=test");
});
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/preloadWsUrl.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const DESKTOP_WS_URL_ARG_PREFIX = "--cut3-desktop-ws-url=";
const DESKTOP_WS_URL_ARG_PREFIX = "--rowl-desktop-ws-url=";

export function resolveInitialDesktopWsUrl(args: {
envValue: string | null | undefined;
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/updateState.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ describe("getAutoUpdateDisabledReason", () => {
appImage: undefined,
disabledByEnv: true,
}),
).toContain("CUT3_DISABLE_AUTO_UPDATE");
).toContain("ROWL_DISABLE_AUTO_UPDATE");
});

it("reports linux non-AppImage builds as disabled", () => {
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/updateState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function getAutoUpdateDisabledReason(args: {
return "Automatic updates are only available in packaged production builds.";
}
if (args.disabledByEnv) {
return "Automatic updates are disabled by the CUT3_DISABLE_AUTO_UPDATE setting.";
return "Automatic updates are disabled by the ROWL_DISABLE_AUTO_UPDATE setting.";
}
if (args.platform === "linux" && !args.appImage) {
return "Automatic updates on Linux require running the AppImage build.";
Expand Down
4 changes: 2 additions & 2 deletions apps/server/package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"name": "cut3",
"name": "rowl",
"version": "1.0.1",
"repository": {
"type": "git",
"url": "https://github.com/yappologistic/t3code",
"directory": "apps/server"
},
"bin": {
"cut3": "./dist/index.mjs"
"rowl": "./dist/index.mjs"
},
"files": [
"dist"
Expand Down
8 changes: 4 additions & 4 deletions apps/server/src/codexAppServerManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,8 +454,8 @@ export function normalizeCodexModelSlug(
export function buildCodexInitializeParams() {
return {
clientInfo: {
name: "cut3_desktop",
title: "CUT3 Desktop",
name: "rowl_desktop",
title: "Rowl Desktop",
version: "0.1.0",
},
capabilities: {
Expand Down Expand Up @@ -1084,7 +1084,7 @@ export class CodexAppServerManager extends EventEmitter<CodexAppServerManagerEve
toModel: OPENROUTER_FREE_ROUTER_MODEL,
reason:
openRouterFallbackReason ??
"OpenRouter could not serve the pinned free model and CUT3 retried through the free router.",
"OpenRouter could not serve the pinned free model and Rowl retried through the free router.",
turnId,
});
}
Expand Down Expand Up @@ -1825,7 +1825,7 @@ export class CodexAppServerManager extends EventEmitter<CodexAppServerManagerEve
toModel: OPENROUTER_FREE_ROUTER_MODEL,
reason:
pendingRetry.retryReason ??
"OpenRouter could not serve the pinned free model and CUT3 retried through the free router.",
"OpenRouter could not serve the pinned free model and Rowl retried through the free router.",
turnId,
});
this.updateSession(context, {
Expand Down
52 changes: 26 additions & 26 deletions apps/server/src/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,15 @@ const testLayer = Layer.mergeAll(

const runCli = (
args: ReadonlyArray<string>,
env: Record<string, string> = { CUT3_NO_BROWSER: "true" },
env: Record<string, string> = { ROWL_NO_BROWSER: "true" },
) => {
const uniqueStateDir = `/tmp/t3-cli-state-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
return Command.runWith(t3Cli, { version: "0.0.0-test" })(args).pipe(
Effect.provide(
ConfigProvider.layer(
ConfigProvider.fromEnv({
env: {
CUT3_STATE_DIR: uniqueStateDir,
ROWL_STATE_DIR: uniqueStateDir,
...env,
},
}),
Expand Down Expand Up @@ -134,13 +134,13 @@ it.layer(testLayer)("server CLI command", (it) => {
it.effect("uses env fallbacks when flags are not provided", () =>
Effect.gen(function* () {
yield* runCli([], {
CUT3_MODE: "desktop",
CUT3_PORT: "4999",
CUT3_HOST: "100.88.10.4",
CUT3_STATE_DIR: "/tmp/t3-env-state",
ROWL_MODE: "desktop",
ROWL_PORT: "4999",
ROWL_HOST: "100.88.10.4",
ROWL_STATE_DIR: "/tmp/t3-env-state",
VITE_DEV_SERVER_URL: "http://localhost:5173",
CUT3_NO_BROWSER: "true",
CUT3_AUTH_TOKEN: "env-token",
ROWL_NO_BROWSER: "true",
ROWL_AUTH_TOKEN: "env-token",
});

assert.equal(start.mock.calls.length, 1);
Expand All @@ -157,12 +157,12 @@ it.layer(testLayer)("server CLI command", (it) => {
}),
);

it.effect("prefers --mode over CUT3_MODE", () =>
it.effect("prefers --mode over ROWL_MODE", () =>
Effect.gen(function* () {
findAvailablePort.mockImplementation((_preferred: number) => Effect.succeed(4666));
yield* runCli(["--mode", "web"], {
CUT3_MODE: "desktop",
CUT3_NO_BROWSER: "true",
ROWL_MODE: "desktop",
ROWL_NO_BROWSER: "true",
});

assert.deepStrictEqual(findAvailablePort.mock.calls, [[3773]]);
Expand All @@ -173,10 +173,10 @@ it.layer(testLayer)("server CLI command", (it) => {
}),
);

it.effect("prefers --no-browser over CUT3_NO_BROWSER", () =>
it.effect("prefers --no-browser over ROWL_NO_BROWSER", () =>
Effect.gen(function* () {
yield* runCli(["--no-browser"], {
CUT3_NO_BROWSER: "false",
ROWL_NO_BROWSER: "false",
});

assert.equal(start.mock.calls.length, 1);
Expand All @@ -187,8 +187,8 @@ it.layer(testLayer)("server CLI command", (it) => {
it.effect("opens a tokenized browser url when auth is enabled", () =>
Effect.gen(function* () {
yield* runCli([], {
CUT3_NO_BROWSER: "false",
CUT3_AUTH_TOKEN: "env-token",
ROWL_NO_BROWSER: "false",
ROWL_AUTH_TOKEN: "env-token",
});

assert.deepStrictEqual(openBrowser.mock.calls, [["http://127.0.0.1:3773/?token=env-token"]]);
Expand All @@ -211,8 +211,8 @@ it.layer(testLayer)("server CLI command", (it) => {
it.effect("uses fixed localhost defaults in desktop mode", () =>
Effect.gen(function* () {
yield* runCli([], {
CUT3_MODE: "desktop",
CUT3_NO_BROWSER: "true",
ROWL_MODE: "desktop",
ROWL_NO_BROWSER: "true",
});

assert.equal(findAvailablePort.mock.calls.length, 0);
Expand All @@ -226,9 +226,9 @@ it.layer(testLayer)("server CLI command", (it) => {
it.effect("accepts an ephemeral desktop port from the environment", () =>
Effect.gen(function* () {
yield* runCli([], {
CUT3_MODE: "desktop",
CUT3_PORT: "0",
CUT3_NO_BROWSER: "true",
ROWL_MODE: "desktop",
ROWL_PORT: "0",
ROWL_NO_BROWSER: "true",
});

assert.equal(findAvailablePort.mock.calls.length, 0);
Expand All @@ -242,8 +242,8 @@ it.layer(testLayer)("server CLI command", (it) => {
it.effect("allows overriding desktop host with --host", () =>
Effect.gen(function* () {
yield* runCli(["--host", "0.0.0.0"], {
CUT3_MODE: "desktop",
CUT3_NO_BROWSER: "true",
ROWL_MODE: "desktop",
ROWL_NO_BROWSER: "true",
});

assert.equal(start.mock.calls.length, 1);
Expand All @@ -255,10 +255,10 @@ it.layer(testLayer)("server CLI command", (it) => {
it.effect("supports CLI and env for bootstrap/log websocket toggles", () =>
Effect.gen(function* () {
yield* runCli(["--auto-bootstrap-project-from-cwd"], {
CUT3_MODE: "desktop",
CUT3_LOG_WS_EVENTS: "false",
CUT3_AUTO_BOOTSTRAP_PROJECT_FROM_CWD: "false",
CUT3_NO_BROWSER: "true",
ROWL_MODE: "desktop",
ROWL_LOG_WS_EVENTS: "false",
ROWL_AUTO_BOOTSTRAP_PROJECT_FROM_CWD: "false",
ROWL_NO_BROWSER: "true",
});

assert.equal(start.mock.calls.length, 1);
Expand Down
Loading