Skip to content

[codex] Use updated web splash icon#3672

Closed
bcotrim wants to merge 33 commits into
pingdotgg:mainfrom
bcotrim:mognet/fix-web-icon-background
Closed

[codex] Use updated web splash icon#3672
bcotrim wants to merge 33 commits into
pingdotgg:mainfrom
bcotrim:mognet/fix-web-icon-background

Conversation

@bcotrim

@bcotrim bcotrim commented Jul 3, 2026

Copy link
Copy Markdown

What changed

  • Added a web-only transparent splash icon derived from the current macOS app icon artwork.
  • Updated the web boot shell to use that splash asset instead of the Apple touch icon.
  • Added a subtle drop shadow so the foreground artwork reads cleanly on the dark loading background.

Why

The embedded web startup view was showing an older flat mark and previously used an icon with a dark tile background that did not match the page background. The macOS app icon artwork is the current desired look, but the macOS icon asset itself should stay unchanged.

Impact

The startup/loading screen now shows the updated 3D Mognet artwork without the mismatched background tile. Desktop app icon assets are untouched.

Validation

  • vp check
  • vp run typecheck
  • Verified /mognet-splash-icon.png serves locally with 200 OK.

Note

Update web splash icon and rebrand product from T3 Code to Mognet

  • Renames all branding, environment variables, file paths, storage keys, protocol schemes, and user-facing strings from T3 Code / T3CODE_* to Mognet / MOGNET_* across the entire monorepo
  • Removes Clerk authentication, hosted pairing, relay/cloud connect infrastructure, and DPoP authorization flows from both the desktop and web clients
  • Adds a ScheduledTasks service with persistence, scheduling, and CRUD RPC endpoints (scheduledTasks.list/create/update/delete/runNow), plus a new /scheduled-tasks UI route
  • Adds a ThreadTurnBootstrapDispatcher service and introduces standalone (projectless) chat threads backed by STANDALONE_CHAT_PROJECT_ID
  • Adds terminal discovery and launch via ExternalLauncher.launchTerminal with a shell.openInTerminal RPC endpoint and OpenInTerminalPicker UI
  • Adds a new Mognet MCP toolkit (mognet_thread_start, mognet_delegate_task, scheduled task tools, etc.) registered on the MCP HTTP server
  • Migrates IndexedDB and localStorage keys from t3code:* to mognet:* with transparent legacy fallback reads
  • Risk: environment variables (T3CODE_*), localStorage keys (t3code:*), well-known path (/.well-known/t3/environment), and protocol schemes (t3code://) are no longer read; existing data under old keys requires the migration path or will be lost
📊 Macroscope summarized fb67b14. 174 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

bcotrim and others added 30 commits July 1, 2026 19:01
Align apps with Cotrim design system
Prune mobile and marketing surfaces
Add flexible scheduled task checks across server and web
…trols

Add standalone chat sidebar controls
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5f75d903-90ae-48d8-8c09-136b2d087357

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Jul 3, 2026
@bcotrim bcotrim closed this Jul 3, 2026
const [form, setForm] = useState<FormState>(() => formFromTask(task, defaults));
const [saving, setSaving] = useState(false);

useEffect(() => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium settings/ScheduledTasksSettings.tsx:320

The useEffect at lines 320–325 resets the form state whenever defaults changes. Because defaults is a memo recomputed from visibleProviders, projects, and settings, any background atom update while the dialog is open triggers setForm(formFromTask(task, defaults)), discarding any title, prompt, or model edits the user has already typed. Consider resetting the form only when open or task changes, not on every defaults refresh.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/settings/ScheduledTasksSettings.tsx around line 320:

The `useEffect` at lines 320–325 resets the form state whenever `defaults` changes. Because `defaults` is a memo recomputed from `visibleProviders`, `projects`, and `settings`, any background atom update while the dialog is open triggers `setForm(formFromTask(task, defaults))`, discarding any title, prompt, or model edits the user has already typed. Consider resetting the form only when `open` or `task` changes, not on every `defaults` refresh.

});
const [dialogOpen, setDialogOpen] = useState(false);
const [editingTask, setEditingTask] = useState<ScheduledTaskSnapshot | null>(null);
const [busyTaskId, setBusyTaskId] = useState<string | null>(null);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium settings/ScheduledTasksSettings.tsx:711

busyTaskId stores a single task id, so concurrent mutations on different tasks overwrite each other. If the user triggers an action on task A and then another on task B, the second setBusyTaskId replaces A's id; when either request finishes it resets the shared state to null, re-enabling buttons for a task whose mutation is still in flight. This allows duplicate run, delete, or update requests to be sent for the same task. Consider tracking busy state per task id (e.g. a Set<string> of in-flight ids) instead of a single value.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/settings/ScheduledTasksSettings.tsx around line 711:

`busyTaskId` stores a single task id, so concurrent mutations on different tasks overwrite each other. If the user triggers an action on task A and then another on task B, the second `setBusyTaskId` replaces A's id; when either request finishes it resets the shared state to `null`, re-enabling buttons for a task whose mutation is still in flight. This allows duplicate `run`, `delete`, or `update` requests to be sent for the same task. Consider tracking busy state per task id (e.g. a `Set<string>` of in-flight ids) instead of a single value.

});
}

const project =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium mognet/handlers.ts:309

When standalone === true, resolveNewThreadTarget sets project to null instead of loading the STANDALONE_CHAT_PROJECT_ID project, so the fallback project?.defaultModelSelection is skipped. Starting a standalone thread with no current thread and no explicit modelSelection fails with No modelSelection was supplied... even when the standalone chat project has a default model configured. Consider loading the standalone project so its defaultModelSelection is used as a fallback.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/mcp/toolkits/mognet/handlers.ts around line 309:

When `standalone === true`, `resolveNewThreadTarget` sets `project` to `null` instead of loading the `STANDALONE_CHAT_PROJECT_ID` project, so the fallback `project?.defaultModelSelection` is skipped. Starting a standalone thread with no current thread and no explicit `modelSelection` fails with `No modelSelection was supplied...` even when the standalone chat project has a default model configured. Consider loading the standalone project so its `defaultModelSelection` is used as a fallback.

worktreePath: null,
createdAt,
},
prepareWorktree: {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High mognet/handlers.ts:406

startThread builds bootstrap.prepareWorktree without a branch field in worktree mode. Since ThreadTurnBootstrapDispatcher passes bootstrap.prepareWorktree.branch as newRefName to gitWorkflow.createWorktree, the new worktree is not created on a fresh branch — it either reuses baseBranch or fails when that branch is already checked out, breaking the isolated worktree behavior advertised for workspaceMode: "worktree". Consider generating a unique branch name and including it in prepareWorktree.branch so the worktree gets its own branch.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/mcp/toolkits/mognet/handlers.ts around line 406:

`startThread` builds `bootstrap.prepareWorktree` without a `branch` field in worktree mode. Since `ThreadTurnBootstrapDispatcher` passes `bootstrap.prepareWorktree.branch` as `newRefName` to `gitWorkflow.createWorktree`, the new worktree is not created on a fresh branch — it either reuses `baseBranch` or fails when that branch is already checked out, breaking the isolated worktree behavior advertised for `workspaceMode: "worktree"`. Consider generating a unique branch name and including it in `prepareWorktree.branch` so the worktree gets its own branch.

ReadonlyArray<ScheduledAgentTask>,
ScheduledTaskError
> = Effect.gen(function* () {
const exists = yield* fs.exists(config.scheduledTasksStatePath).pipe(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium src/scheduledTasks.ts:281

The fs.exists call on line 281 maps I/O and permission errors to false via Effect.orElseSucceed(() => false), so when the state file is inaccessible the service treats it as missing and returns an empty task list instead of reporting the error. This causes all scheduled tasks to silently disappear from the API until the process is restarted. Consider propagating the fs.exists error as a ScheduledTaskError rather than swallowing it, so the read failure surfaces instead of being masked as an empty file.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/scheduledTasks.ts around line 281:

The `fs.exists` call on line 281 maps I/O and permission errors to `false` via `Effect.orElseSucceed(() => false)`, so when the state file is inaccessible the service treats it as missing and returns an empty task list instead of reporting the error. This causes all scheduled tasks to silently disappear from the API until the process is restarted. Consider propagating the `fs.exists` error as a `ScheduledTaskError` rather than swallowing it, so the read failure surfaces instead of being masked as an empty file.

<Button variant="outline" onClick={() => onOpenChange(false)}>
Cancel
</Button>
<Button disabled={!validInput || saving} onClick={() => void submit()}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium settings/ScheduledTasksSettings.tsx:680

When no providers are available, defaults.providerInstanceId falls back to "codex", and validInput only checks that providerInstanceId is non-empty — it never verifies the id exists in providers. The Create button becomes enabled once a title and prompt are entered, and toScheduledTaskInput persists a task with an unregistered provider id. The task later fails at runtime with No provider instance registered for id .... Consider disabling the Create button when visibleProviders is empty, or rejecting the form in toScheduledTaskInput when the selected id is not in providers.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/settings/ScheduledTasksSettings.tsx around line 680:

When no providers are available, `defaults.providerInstanceId` falls back to `"codex"`, and `validInput` only checks that `providerInstanceId` is non-empty — it never verifies the id exists in `providers`. The Create button becomes enabled once a title and prompt are entered, and `toScheduledTaskInput` persists a task with an unregistered provider id. The task later fails at runtime with `No provider instance registered for id ...`. Consider disabling the Create button when `visibleProviders` is empty, or rejecting the form in `toScheduledTaskInput` when the selected id is not in `providers`.

Comment on lines +623 to +624
const invocation = yield* McpInvocationContext.McpInvocationContext;
const includeSourceContext = input.includeSourceContext ?? true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium mognet/handlers.ts:623

delegateTask calls getThreadOrFail and getProjectOrFail before startThread invokes requireOrchestration, so a caller without the orchestration capability still gets Thread '…' was not found. or Project '…' was not found. errors. This leaks whether threads and projects exist before the capability check eventually rejects the operation. Consider calling requireOrchestration("delegate_task") at the top of delegateTask, before any snapshot queries.

  const invocation = yield* McpInvocationContext.McpInvocationContext;
+  yield* requireOrchestration("delegate_task");
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/mcp/toolkits/mognet/handlers.ts around lines 623-624:

`delegateTask` calls `getThreadOrFail` and `getProjectOrFail` before `startThread` invokes `requireOrchestration`, so a caller without the `orchestration` capability still gets `Thread '…' was not found.` or `Project '…' was not found.` errors. This leaks whether threads and projects exist before the capability check eventually rejects the operation. Consider calling `requireOrchestration("delegate_task")` at the top of `delegateTask`, before any snapshot queries.

path: Path.Path,
verbose: boolean,
) {
function generateMacIcns(sourcePng: string, targetIcns: string, verbose: boolean) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 Critical scripts/build-desktop-artifact.ts:768

generateMacIcns runs sips -s format icns, but sips does not support icns as an output format — it only handles raster formats like png, jpeg, and tiff. This command fails, so every mac desktop build breaks when staging the .icns icon. The previous iconset + iconutil flow is required to produce a valid .icns file — consider restoring it.

🤖 Copy this AI Prompt to have your agent fix this:
In file @scripts/build-desktop-artifact.ts around line 768:

`generateMacIcns` runs `sips -s format icns`, but `sips` does not support `icns` as an output format — it only handles raster formats like `png`, `jpeg`, and `tiff`. This command fails, so every mac desktop build breaks when staging the `.icns` icon. The previous `iconset` + `iconutil` flow is required to produce a valid `.icns` file — consider restoring it.

export const layer = MognetToolkitRegistrationLive.pipe(Layer.provideMerge(McpTransportLive));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium mcp/McpHttpServer.ts:228

Changing layer to export MognetToolkitRegistrationLive instead of PreviewToolkitRegistrationLive exposes the entire Mognet toolkit on the public /mcp endpoint for every issued bearer token. MognetToolkitRegistrationLive merges the preview registration with MognetWorkflowToolkitRegistrationLive, so the endpoint now serves mognet_scheduled_tasks_create, mognet_scheduled_tasks_delete, mognet_thread_start, mognet_delegate_task, and mognet_thread_handoff. Any provider MCP credential can now mutate orchestration state and scheduled tasks, a significant privilege expansion from the previous preview-only surface. If this is intentional, consider documenting why all tokens receive destructive orchestration and scheduled-task capabilities. Otherwise, restore PreviewToolkitRegistrationLive or gate the Mognet toolkit registration behind a capability check.

-export const layer = MognetToolkitRegistrationLive.pipe(Layer.provideMerge(McpTransportLive));
+export const layer = PreviewToolkitRegistrationLive.pipe(Layer.provideMerge(McpTransportLive));
Also found in 1 other location(s)

apps/server/src/mcp/McpSessionRegistry.ts:117

issue() now grants every provider-issued MCP credential the &#34;orchestration&#34; and &#34;scheduled-tasks&#34; capabilities in addition to &#34;preview&#34;. The same bearer token is accepted by McpHttpServer for the full MognetToolkit, and handlers such as mognet_thread_start, mognet_thread_handoff, and all scheduled-task mutation endpoints only check invocation.capabilities.has(...). Any provider process that receives its normal MCP token can now create/open threads and create/update/delete/run scheduled tasks, which broadens a previously preview-scoped credential into one that can mutate application state.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/mcp/McpHttpServer.ts around line 228:

Changing `layer` to export `MognetToolkitRegistrationLive` instead of `PreviewToolkitRegistrationLive` exposes the entire Mognet toolkit on the public `/mcp` endpoint for every issued bearer token. `MognetToolkitRegistrationLive` merges the preview registration with `MognetWorkflowToolkitRegistrationLive`, so the endpoint now serves `mognet_scheduled_tasks_create`, `mognet_scheduled_tasks_delete`, `mognet_thread_start`, `mognet_delegate_task`, and `mognet_thread_handoff`. Any provider MCP credential can now mutate orchestration state and scheduled tasks, a significant privilege expansion from the previous preview-only surface. If this is intentional, consider documenting why all tokens receive destructive orchestration and scheduled-task capabilities. Otherwise, restore `PreviewToolkitRegistrationLive` or gate the Mognet toolkit registration behind a capability check.

Also found in 1 other location(s):
- apps/server/src/mcp/McpSessionRegistry.ts:117 -- `issue()` now grants every provider-issued MCP credential the `"orchestration"` and `"scheduled-tasks"` capabilities in addition to `"preview"`. The same bearer token is accepted by `McpHttpServer` for the full `MognetToolkit`, and handlers such as `mognet_thread_start`, `mognet_thread_handoff`, and all scheduled-task mutation endpoints only check `invocation.capabilities.has(...)`. Any provider process that receives its normal MCP token can now create/open threads and create/update/delete/run scheduled tasks, which broadens a previously preview-scoped credential into one that can mutate application state.

}

try {
isomorphicLocalStorage.setItem(key, legacyValue);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium hooks/useLocalStorage.ts:53

When removeLocalStorageItem removes the mognet:* key, read falls back to the unmigrated t3code:* legacy key, returns the stale legacy value, and re-writes it to the mognet:* key — so the deleted item reappears on the next read. Consider removing the legacy key as part of the migration in read, or deleting it in removeLocalStorageItem.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/hooks/useLocalStorage.ts around line 53:

When `removeLocalStorageItem` removes the `mognet:*` key, `read` falls back to the unmigrated `t3code:*` legacy key, returns the stale legacy value, and re-writes it to the `mognet:*` key — so the deleted item reappears on the next read. Consider removing the legacy key as part of the migration in `read`, or deleting it in `removeLocalStorageItem`.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant