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
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: function handle
created: 2026-10-15T04:08:49Z
norm: '1'
sig: e597b5fbc8e664ce
body_hash: 4c0a5f447f3453d7
raw_hash: 277527dea93aa68f
vouched: 2026-10-16T22:11:39Z
body_hash: aae4da1d5b13a0a7
raw_hash: 887a83004e69e816
vouched: 2026-10-19T17:59:13Z
lines: 266-519
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: function handle
created: 2026-10-15T06:00:20Z
norm: '1'
sig: e597b5fbc8e664ce
body_hash: 4c0a5f447f3453d7
raw_hash: 277527dea93aa68f
vouched: 2026-10-16T22:11:39Z
body_hash: aae4da1d5b13a0a7
raw_hash: 887a83004e69e816
vouched: 2026-10-19T17:59:13Z
lines: 281-561
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ id: 01M5314FQ002GKKHTQ5G9Q4NZJ
anchor: function targets
created: 2026-10-16T18:56:03Z
norm: '1'
sig: 7b9616ffd24e6d4f
body_hash: 601506fe4d4d38d9
raw_hash: 0f2a5a6a1e5af55a
vouched: 2026-10-19T16:56:54Z
sig: 002f9c457b031ab4
body_hash: 85d4201c6260eec4
raw_hash: 8782a699c3cff424
vouched: 2026-10-19T17:59:13Z
lines: 64-79
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: function resolveIcon
created: 2026-10-16T21:22:34Z
norm: '1'
sig: d6f0475e7b3b3b6a
body_hash: ac51fa4986c3d09c
raw_hash: f8c73fa082615d42
vouched: 2026-10-19T16:56:54Z
body_hash: 9f404a3e4bee814d
raw_hash: cd2cb0d75cfe2527
vouched: 2026-10-19T17:59:13Z
lines: 64-109
---

Expand Down
1 change: 0 additions & 1 deletion apps/app/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ function row(
lifecycle: channel.state === "archived" ? "archived" : "live",
private: false,
cloud: place.kind === "cloud",
hosted: place.kind === "hosted",
mine: channel.owner === user,
member: true,
capabilities: {
Expand Down
6 changes: 3 additions & 3 deletions apps/app/src/channel-access.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ function reach(channel: Listing): { agents: string; confirm: string; desktop: bo
};
}

/** The machine the channel's tools run on: its host's, or a container on the compute service. */
/** Where the channel runs: a cloud for a hosted or compute channel, otherwise its host. */
function Machine({ channel }: { channel: Listing }) {
const place = placement(channel);
const [Icon, name, detail] = place.kind === "cloud"
? [IconCloud, "Cloud", `Tools run in a container on ${place.service}.`]
: place.kind === "hosted"
? [
IconLaptop,
IconCloud,
place.workspace,
`Hosted on ${place.service}. Tools run on ${place.workspace}.`,
]
Expand All @@ -60,7 +60,7 @@ function Machine({ channel }: { channel: Listing }) {
<Tooltip>
<TooltipTrigger
render={
<span className="mr-1 inline-flex min-w-0 items-center gap-1 text-xs text-muted-foreground" />
<span className="mr-3 inline-flex min-w-0 items-center gap-1 text-xs text-muted-foreground" />
}
>
<Icon className="size-3.5 shrink-0" aria-hidden />
Expand Down
8 changes: 2 additions & 6 deletions apps/app/src/channel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
Sidebar,
useLayoutRight,
} from "@ace/ui";
import { IconCloud, IconHash, IconRadar } from "@ace/ui/icons";
import { IconCloud, IconHash } from "@ace/ui/icons";

import { ChannelAccess } from "./channel-access";
import { EFFORTS } from "./composer";
Expand Down Expand Up @@ -323,11 +323,7 @@ export function Channel(
: remote
? `${channel.name} · ${channel.host}`
: channel.name}
icon={place.kind === "cloud"
? place.stopped ? StoppedCloud : IconCloud
: place.kind === "hosted"
? IconRadar
: IconHash}
icon={place.kind === "cloud" ? place.stopped ? StoppedCloud : IconCloud : IconHash}
chat={chat}
changed={changed}
opener={opener}
Expand Down
8 changes: 0 additions & 8 deletions apps/app/src/dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import {
IconLaptop,
IconMessage,
IconPlus,
IconRadar,
IconRotate,
} from "@ace/ui/icons";
import type { GithubList } from "@ace/channel/protocol";
Expand Down Expand Up @@ -541,13 +540,6 @@ export function Dashboard(
aria-label="Cloud channel"
/>
)
: channel.hosted
? (
<IconRadar
className="size-4 shrink-0 text-muted-foreground"
aria-label="Hosted channel"
/>
)
: <IconHash className="size-4 shrink-0 text-muted-foreground" aria-hidden />}
<span className="min-w-0 flex-1">
<span className="block truncate">{channel.name}</span>
Expand Down
2 changes: 1 addition & 1 deletion apps/app/src/layout/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ function Add({ onAdd }: { onAdd: (choice: Choice) => void }) {
variant="ghost"
size="icon-sm"
aria-label="New tab"
className="mx-0.5 shrink-0 text-muted-foreground electrobun-webkit-app-region-no-drag"
className="mr-2 ml-0.5 shrink-0 text-muted-foreground electrobun-webkit-app-region-no-drag"
/>
}
>
Expand Down
2 changes: 1 addition & 1 deletion apps/host/src/gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ async function handle(
return archived.length;
}
case "move-targets":
return catalog.owns(request.channel) ? targets(request.channel) : [];
return catalog.owns(request.channel) ? targets(request.channel, name) : [];
case "move": {
if (!catalog.owns(request.channel)) {
throw new Error("Move channels from the host that runs them");
Expand Down
6 changes: 3 additions & 3 deletions apps/host/src/move.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* both copies from running while the move is under way, and an unknown activation keeps it.
*/
import { existsSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
import { hostname } from "node:os";
import { join } from "node:path";

import { openNodeSqliteDatabase } from "@earendil-works/pi-durable/storage/sqlite/node";
Expand Down Expand Up @@ -65,15 +64,16 @@ function movable(record: catalog.Listing): void {
/** The target that moves a local channel to a cloud workspace on the team's compute service. */
const COMPUTE = "compute";

export async function targets(id: string): Promise<MoveTarget[]> {
/** `host` is this host's name as the app shows it, its tailnet machine name when it has one. */
export async function targets(id: string, host: string): Promise<MoveTarget[]> {
const record = catalog.read(id);
try {
movable(record);
} catch {
return [];
}
if (record.hosted) {
return [{ target: "local", label: `this host (${hostname()})`, place: "local" }];
return [{ target: "local", label: `this host (${host})`, place: "local" }];
}
const team = directory.read().hosted;
const hosted = new Set([
Expand Down
16 changes: 12 additions & 4 deletions packages/ui/src/components/session-item/session-item-actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import {
IconPin as Pin,
IconPinOff as PinSlash,
IconPlay as Play,
IconRadar as Radar,
IconRotate as Rebuild,
IconStop as Stop,
IconTrash as Trash,
Expand Down Expand Up @@ -66,7 +65,13 @@ type RowMenuProps = ActionProps & {
children: ReactNode;
};

const PLACES = { local: Hash, hosted: Radar, cloud: Cloud };
const PLACES = { local: Hash, hosted: Cloud, cloud: Cloud };
// "Cloud" and "cloud workspace" alone don't say what moves, so each item says where tools run.
const HINTS = {
local: "Chat and tools run on this Mac",
hosted: "Chat moves; tools stay on this Mac",
cloud: "Chat and tools move to a cloud container",
};

type Destinations =
| { state: "loading" }
Expand Down Expand Up @@ -190,8 +195,11 @@ function MoveSection(
onMove(target);
}}
>
<Icon className="size-3.5" />
<span className="min-w-0 flex-1 truncate">Move to {target.label}</span>
<Icon className="size-3.5 self-start mt-0.5" />
<span className="flex min-w-0 flex-1 flex-col">
<span className="truncate">Move to {target.label}</span>
<span className="truncate text-muted-foreground">{HINTS[target.place]}</span>
</span>
{moving === target.target && (
<span className="shrink-0 text-muted-foreground">Moving…</span>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
IconMessage as Msg,
IconPullRequest,
IconPullRequestClosed,
IconRadar,
} from "../../icons";

type BadgeState = ReturnType<typeof resolveBadge>;
Expand Down Expand Up @@ -106,7 +105,6 @@ function resolveIcon(data: SidebarRow) {
}
if (data.private) return <IconLock aria-label="Private channel" />;
if (data.cloud) return <IconCloud aria-label="Cloud channel" />;
if (data.hosted) return <IconRadar aria-label="Hosted channel" />;
return <IconHash aria-label="Channel" />;
}

Expand Down
2 changes: 0 additions & 2 deletions packages/ui/src/components/session-item/session-item.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ export type SidebarRow = {
private: boolean;
/** Runs on the team's cloud compute rather than a teammate's machine. */
cloud?: boolean;
/** Lives on the team's hosting service while a host runs its tools. */
hosted?: boolean;
mine: boolean;
member: boolean;
/** Omitted by local/legacy callers; explicit peer policy controls administrative actions. */
Expand Down
2 changes: 0 additions & 2 deletions packages/ui/src/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ import {
PinOff,
Play,
Plus,
Radar,
RotateCw,
Rows2,
Search,
Expand Down Expand Up @@ -194,7 +193,6 @@ export const IconPointer = outline(MousePointer2);
export const IconPullRequest = outline(GitPullRequest);
export const IconPullRequestClosed = outline(GitPullRequestClosed);
export const IconPush = outline(ArrowUpFromLine);
export const IconRadar = outline(Radar);
export const IconReact = outline(FaceSlightlySmilingPlus);
export const IconRecord = outline(CircleDot);
export const IconReview = outline(MessageSquareDiff);
Expand Down