refactor(project): drop persisted Project.sandboxes column

The Project row stored a sandboxes string array that duplicated what git
already tracks. The /experimental/worktree GET handler now reads from
`Worktree.list()` (git worktree list --porcelain) instead, the write-side
addSandbox/removeSandbox bookkeeping is gone, and the column is dropped
from the schema with a Drizzle migration. The app maps the live list onto
project.worktrees client-side instead of reading project.sandboxes.
This commit is contained in:
Kit Langton 2026-05-11 11:07:36 -04:00
commit c4132543c3
31 changed files with 1866 additions and 519 deletions

View file

@ -1236,7 +1236,7 @@ export class Worktree extends HeyApiClient {
/**
* List worktrees
*
* List all sandbox worktrees for the current project.
* List all git worktrees for the current project.
*/
public list<ThrowOnError extends boolean = false>(
parameters?: {

View file

@ -5,6 +5,12 @@ export type ClientOptions = {
}
export type Event =
| EventTuiPromptAppend
| EventTuiCommandExecute
| EventTuiToastShow1
| EventTuiSessionSelect
| EventServerConnected
| EventGlobalDisposed
| EventServerInstanceDisposed
| EventFileEdited
| EventFileWatcherUpdated
@ -24,10 +30,6 @@ export type Event =
| EventSessionStatus
| EventSessionIdle
| EventSessionCompacted
| EventTuiPromptAppend
| EventTuiCommandExecute
| EventTuiToastShow1
| EventTuiSessionSelect
| EventMcpToolsChanged
| EventMcpBrowserOpenFailed
| EventCommandExecuted
@ -75,8 +77,6 @@ export type Event =
| EventSessionNextCompactionStarted
| EventSessionNextCompactionDelta
| EventSessionNextCompactionEnded
| EventServerConnected
| EventGlobalDisposed
export type OAuth = {
type: "oauth"
@ -103,6 +103,61 @@ export type WellKnownAuth = {
export type Auth = OAuth | ApiAuth | WellKnownAuth
export type EventTuiPromptAppend = {
id: string
type: "tui.prompt.append"
properties: {
text: string
}
}
export type EventTuiCommandExecute = {
id: string
type: "tui.command.execute"
properties: {
command:
| "session.list"
| "session.new"
| "session.share"
| "session.interrupt"
| "session.compact"
| "session.page.up"
| "session.page.down"
| "session.line.up"
| "session.line.down"
| "session.half.page.up"
| "session.half.page.down"
| "session.first"
| "session.last"
| "prompt.clear"
| "prompt.submit"
| "agent.cycle"
| string
}
}
export type EventTuiToastShow = {
id: string
type: "tui.toast.show"
properties: {
title?: string
message: string
variant: "info" | "success" | "warning" | "error"
duration?: number
}
}
export type EventTuiSessionSelect = {
id: string
type: "tui.session.select"
properties: {
/**
* Session ID to navigate to
*/
sessionID: string
}
}
export type PermissionRequest = {
id: string
sessionID: string
@ -280,61 +335,6 @@ export type SessionStatus =
type: "busy"
}
export type EventTuiPromptAppend = {
id: string
type: "tui.prompt.append"
properties: {
text: string
}
}
export type EventTuiCommandExecute = {
id: string
type: "tui.command.execute"
properties: {
command:
| "session.list"
| "session.new"
| "session.share"
| "session.interrupt"
| "session.compact"
| "session.page.up"
| "session.page.down"
| "session.line.up"
| "session.line.down"
| "session.half.page.up"
| "session.half.page.down"
| "session.first"
| "session.last"
| "prompt.clear"
| "prompt.submit"
| "agent.cycle"
| string
}
}
export type EventTuiToastShow = {
id: string
type: "tui.toast.show"
properties: {
title?: string
message: string
variant: "info" | "success" | "warning" | "error"
duration?: number
}
}
export type EventTuiSessionSelect = {
id: string
type: "tui.session.select"
properties: {
/**
* Session ID to navigate to
*/
sessionID: string
}
}
export type Project = {
id: string
worktree: string
@ -356,7 +356,6 @@ export type Project = {
updated: number
initialized?: number
}
sandboxes: Array<string>
}
export type Pty = {
@ -779,6 +778,12 @@ export type GlobalEvent = {
project?: string
workspace?: string
payload:
| EventTuiPromptAppend
| EventTuiCommandExecute
| EventTuiToastShow
| EventTuiSessionSelect
| EventServerConnected
| EventGlobalDisposed
| EventServerInstanceDisposed
| EventFileEdited
| EventFileWatcherUpdated
@ -798,10 +803,6 @@ export type GlobalEvent = {
| EventSessionStatus
| EventSessionIdle
| EventSessionCompacted
| EventTuiPromptAppend
| EventTuiCommandExecute
| EventTuiToastShow
| EventTuiSessionSelect
| EventMcpToolsChanged
| EventMcpBrowserOpenFailed
| EventCommandExecuted
@ -849,8 +850,6 @@ export type GlobalEvent = {
| EventSessionNextCompactionStarted
| EventSessionNextCompactionDelta
| EventSessionNextCompactionEnded
| EventServerConnected
| EventGlobalDisposed
| SyncEventMessageUpdated
| SyncEventMessageRemoved
| SyncEventMessagePartUpdated
@ -2331,6 +2330,22 @@ export type SyncEventSessionNextCompactionEnded = {
}
}
export type EventServerConnected = {
id: string
type: "server.connected"
properties: {
[key: string]: unknown
}
}
export type EventGlobalDisposed = {
id: string
type: "global.disposed"
properties: {
[key: string]: unknown
}
}
export type EventServerInstanceDisposed = {
id: string
type: "server.instance.disposed"
@ -3057,22 +3072,6 @@ export type EventSessionNextCompactionEnded = {
}
}
export type EventServerConnected = {
id: string
type: "server.connected"
properties: {
[key: string]: unknown
}
}
export type EventGlobalDisposed = {
id: string
type: "global.disposed"
properties: {
[key: string]: unknown
}
}
export type SessionInfo = {
id: string
parentID?: string

View file

@ -1015,7 +1015,7 @@
}
}
},
"description": "List all sandbox worktrees for the current project.",
"description": "List all git worktrees for the current project.",
"summary": "List worktrees",
"x-codeSamples": [
{
@ -8878,6 +8878,24 @@
"schemas": {
"Event": {
"anyOf": [
{
"$ref": "#/components/schemas/Event.tui.prompt.append"
},
{
"$ref": "#/components/schemas/Event.tui.command.execute"
},
{
"$ref": "#/components/schemas/EventTuiToastShow1"
},
{
"$ref": "#/components/schemas/Event.tui.session.select"
},
{
"$ref": "#/components/schemas/EventServerConnected"
},
{
"$ref": "#/components/schemas/EventGlobalDisposed"
},
{
"$ref": "#/components/schemas/EventServerInstanceDisposed"
},
@ -8935,18 +8953,6 @@
{
"$ref": "#/components/schemas/EventSessionCompacted"
},
{
"$ref": "#/components/schemas/Event.tui.prompt.append"
},
{
"$ref": "#/components/schemas/Event.tui.command.execute"
},
{
"$ref": "#/components/schemas/EventTuiToastShow1"
},
{
"$ref": "#/components/schemas/Event.tui.session.select"
},
{
"$ref": "#/components/schemas/EventMcpToolsChanged"
},
@ -9087,12 +9093,6 @@
},
{
"$ref": "#/components/schemas/EventSessionNextCompactionEnded"
},
{
"$ref": "#/components/schemas/EventServerConnected"
},
{
"$ref": "#/components/schemas/EventGlobalDisposed"
}
]
},
@ -9173,6 +9173,140 @@
}
]
},
"Event.tui.prompt.append": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["tui.prompt.append"]
},
"properties": {
"type": "object",
"properties": {
"text": {
"type": "string"
}
},
"required": ["text"],
"additionalProperties": false
}
},
"required": ["id", "type", "properties"],
"additionalProperties": false
},
"Event.tui.command.execute": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["tui.command.execute"]
},
"properties": {
"type": "object",
"properties": {
"command": {
"anyOf": [
{
"type": "string",
"enum": [
"session.list",
"session.new",
"session.share",
"session.interrupt",
"session.compact",
"session.page.up",
"session.page.down",
"session.line.up",
"session.line.down",
"session.half.page.up",
"session.half.page.down",
"session.first",
"session.last",
"prompt.clear",
"prompt.submit",
"agent.cycle"
]
},
{
"type": "string"
}
]
}
},
"required": ["command"],
"additionalProperties": false
}
},
"required": ["id", "type", "properties"],
"additionalProperties": false
},
"Event.tui.toast.show": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["tui.toast.show"]
},
"properties": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"message": {
"type": "string"
},
"variant": {
"type": "string",
"enum": ["info", "success", "warning", "error"]
},
"duration": {
"type": "integer",
"exclusiveMinimum": 0
}
},
"required": ["message", "variant"],
"additionalProperties": false
}
},
"required": ["id", "type", "properties"],
"additionalProperties": false
},
"Event.tui.session.select": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["tui.session.select"]
},
"properties": {
"type": "object",
"properties": {
"sessionID": {
"type": "string",
"pattern": "^ses",
"description": "Session ID to navigate to"
}
},
"required": ["sessionID"],
"additionalProperties": false
}
},
"required": ["id", "type", "properties"],
"additionalProperties": false
},
"PermissionRequest": {
"type": "object",
"properties": {
@ -9632,140 +9766,6 @@
}
]
},
"Event.tui.prompt.append": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["tui.prompt.append"]
},
"properties": {
"type": "object",
"properties": {
"text": {
"type": "string"
}
},
"required": ["text"],
"additionalProperties": false
}
},
"required": ["id", "type", "properties"],
"additionalProperties": false
},
"Event.tui.command.execute": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["tui.command.execute"]
},
"properties": {
"type": "object",
"properties": {
"command": {
"anyOf": [
{
"type": "string",
"enum": [
"session.list",
"session.new",
"session.share",
"session.interrupt",
"session.compact",
"session.page.up",
"session.page.down",
"session.line.up",
"session.line.down",
"session.half.page.up",
"session.half.page.down",
"session.first",
"session.last",
"prompt.clear",
"prompt.submit",
"agent.cycle"
]
},
{
"type": "string"
}
]
}
},
"required": ["command"],
"additionalProperties": false
}
},
"required": ["id", "type", "properties"],
"additionalProperties": false
},
"Event.tui.toast.show": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["tui.toast.show"]
},
"properties": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"message": {
"type": "string"
},
"variant": {
"type": "string",
"enum": ["info", "success", "warning", "error"]
},
"duration": {
"type": "integer",
"exclusiveMinimum": 0
}
},
"required": ["message", "variant"],
"additionalProperties": false
}
},
"required": ["id", "type", "properties"],
"additionalProperties": false
},
"Event.tui.session.select": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["tui.session.select"]
},
"properties": {
"type": "object",
"properties": {
"sessionID": {
"type": "string",
"pattern": "^ses",
"description": "Session ID to navigate to"
}
},
"required": ["sessionID"],
"additionalProperties": false
}
},
"required": ["id", "type", "properties"],
"additionalProperties": false
},
"Project": {
"type": "object",
"properties": {
@ -9825,15 +9825,9 @@
},
"required": ["created", "updated"],
"additionalProperties": false
},
"sandboxes": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["id", "worktree", "time", "sandboxes"],
"required": ["id", "worktree", "time"],
"additionalProperties": false
},
"Pty": {
@ -11145,6 +11139,24 @@
},
"payload": {
"anyOf": [
{
"$ref": "#/components/schemas/Event.tui.prompt.append"
},
{
"$ref": "#/components/schemas/Event.tui.command.execute"
},
{
"$ref": "#/components/schemas/Event.tui.toast.show"
},
{
"$ref": "#/components/schemas/Event.tui.session.select"
},
{
"$ref": "#/components/schemas/EventServerConnected"
},
{
"$ref": "#/components/schemas/EventGlobalDisposed"
},
{
"$ref": "#/components/schemas/EventServerInstanceDisposed"
},
@ -11202,18 +11214,6 @@
{
"$ref": "#/components/schemas/EventSessionCompacted"
},
{
"$ref": "#/components/schemas/Event.tui.prompt.append"
},
{
"$ref": "#/components/schemas/Event.tui.command.execute"
},
{
"$ref": "#/components/schemas/Event.tui.toast.show"
},
{
"$ref": "#/components/schemas/Event.tui.session.select"
},
{
"$ref": "#/components/schemas/EventMcpToolsChanged"
},
@ -11355,12 +11355,6 @@
{
"$ref": "#/components/schemas/EventSessionNextCompactionEnded"
},
{
"$ref": "#/components/schemas/EventServerConnected"
},
{
"$ref": "#/components/schemas/EventGlobalDisposed"
},
{
"$ref": "#/components/schemas/SyncEventMessageUpdated"
},
@ -15859,6 +15853,42 @@
"required": ["type", "name", "id", "seq", "aggregateID", "data"],
"additionalProperties": false
},
"EventServerConnected": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["server.connected"]
},
"properties": {
"type": "object",
"properties": {}
}
},
"required": ["id", "type", "properties"],
"additionalProperties": false
},
"EventGlobalDisposed": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["global.disposed"]
},
"properties": {
"type": "object",
"properties": {}
}
},
"required": ["id", "type", "properties"],
"additionalProperties": false
},
"EventServerInstanceDisposed": {
"type": "object",
"properties": {
@ -18062,42 +18092,6 @@
"required": ["id", "type", "properties"],
"additionalProperties": false
},
"EventServerConnected": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["server.connected"]
},
"properties": {
"type": "object",
"properties": {}
}
},
"required": ["id", "type", "properties"],
"additionalProperties": false
},
"EventGlobalDisposed": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["global.disposed"]
},
"properties": {
"type": "object",
"properties": {}
}
},
"required": ["id", "type", "properties"],
"additionalProperties": false
},
"SessionInfo": {
"type": "object",
"properties": {