feat(core): store relative path for sessions (#24704)

This commit is contained in:
James Long 2026-04-28 11:51:24 -04:00 committed by GitHub
parent ea3c6c3481
commit 2c2fc3499b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 1460 additions and 4 deletions

View file

@ -0,0 +1 @@
ALTER TABLE `session` ADD `path` text;

File diff suppressed because it is too large Load diff

View file

@ -44,6 +44,7 @@ export function toPartialRow(info: DeepPartial<Session.Info>) {
parent_id: grab(info, "parentID"),
slug: grab(info, "slug"),
directory: grab(info, "directory"),
path: grab(info, "path"),
title: grab(info, "title"),
version: grab(info, "version"),
share_url: grab(info, "share", (v) => grab(v, "url")),

View file

@ -24,6 +24,7 @@ export const SessionTable = sqliteTable(
parent_id: text().$type<SessionID>(),
slug: text().notNull(),
directory: text().notNull(),
path: text(),
title: text().notNull(),
version: text().notNull(),
share_url: text(),

View file

@ -74,6 +74,7 @@ export function fromRow(row: SessionRow): Info {
projectID: row.project_id,
workspaceID: row.workspace_id ?? undefined,
directory: row.directory,
path: row.path ?? undefined,
parentID: row.parent_id ?? undefined,
title: row.title,
version: row.version,
@ -98,6 +99,7 @@ export function toRow(info: Info) {
parent_id: info.parentID,
slug: info.slug,
directory: info.directory,
path: info.path,
title: info.title,
version: info.version,
share_url: info.share?.url,
@ -124,6 +126,10 @@ function getForkedTitle(title: string): string {
return `${title} (fork #1)`
}
function sessionPath(worktree: string, cwd: string) {
return path.relative(path.resolve(worktree), cwd).replaceAll("\\", "/")
}
const Summary = Schema.Struct({
additions: Schema.Number,
deletions: Schema.Number,
@ -155,6 +161,7 @@ export const Info = Schema.Struct({
projectID: ProjectID,
workspaceID: optionalOmitUndefined(WorkspaceID),
directory: Schema.String,
path: optionalOmitUndefined(Schema.String),
parentID: optionalOmitUndefined(SessionID),
summary: optionalOmitUndefined(Summary),
share: optionalOmitUndefined(Share),
@ -245,6 +252,7 @@ const UpdatedInfo = Schema.Struct({
projectID: Schema.optional(Schema.NullOr(ProjectID)),
workspaceID: Schema.optional(Schema.NullOr(WorkspaceID)),
directory: Schema.optional(Schema.NullOr(Schema.String)),
path: Schema.optional(Schema.NullOr(Schema.String)),
parentID: Schema.optional(Schema.NullOr(SessionID)),
summary: Schema.optional(Schema.NullOr(Summary)),
share: Schema.optional(UpdatedShare),
@ -442,6 +450,7 @@ export const layer: Layer.Layer<Service, never, Bus.Service | Storage.Service> =
parentID?: SessionID
workspaceID?: WorkspaceID
directory: string
path?: string
permission?: Permission.Ruleset
}) {
const ctx = yield* InstanceState.context
@ -451,6 +460,7 @@ export const layer: Layer.Layer<Service, never, Bus.Service | Storage.Service> =
version: InstallationVersion,
projectID: ctx.project.id,
directory: input.directory,
path: input.path,
workspaceID: input.workspaceID,
parentID: input.parentID,
title: input.title ?? createDefaultTitle(!!input.parentID),
@ -566,11 +576,12 @@ export const layer: Layer.Layer<Service, never, Bus.Service | Storage.Service> =
permission?: Permission.Ruleset
workspaceID?: WorkspaceID
}) {
const directory = yield* InstanceState.directory
const ctx = yield* InstanceState.context
const workspace = yield* InstanceState.workspaceID
return yield* createNext({
parentID: input?.parentID,
directory,
directory: ctx.directory,
path: sessionPath(ctx.worktree, ctx.directory),
title: input?.title,
permission: input?.permission,
workspaceID: workspace,
@ -578,11 +589,12 @@ export const layer: Layer.Layer<Service, never, Bus.Service | Storage.Service> =
})
const fork = Effect.fn("Session.fork")(function* (input: { sessionID: SessionID; messageID?: MessageID }) {
const directory = yield* InstanceState.directory
const ctx = yield* InstanceState.context
const original = yield* get(input.sessionID)
const title = getForkedTitle(original.title)
const session = yield* createNext({
directory,
directory: ctx.directory,
path: sessionPath(ctx.worktree, ctx.directory),
workspaceID: original.workspaceID,
title,
})

View file

@ -208,6 +208,7 @@ export async function run(db: SQLiteBunDatabase<any, any> | NodeSQLiteDatabase<a
parent_id: data.parentID ?? null,
slug: data.slug ?? "",
directory: data.directory ?? "",
path: data.path ?? null,
title: data.title ?? "",
version: data.version ?? "",
share_url: data.share?.url ?? null,

View file

@ -59,6 +59,7 @@ describe("Session.Info", () => {
projectID,
workspaceID,
directory: "/tmp/proj",
path: "packages/opencode",
parentID: sessionIDChild,
summary: {
additions: 10,

View file

@ -54,6 +54,7 @@ describe("session.created event", () => {
expect(receivedInfo?.id).toBe(info.id)
expect(receivedInfo?.projectID).toBe(info.projectID)
expect(receivedInfo?.directory).toBe(info.directory)
expect(receivedInfo?.path).toBe(info.path)
expect(receivedInfo?.title).toBe(info.title)
await remove(info.id)

View file

@ -936,6 +936,7 @@ export type Session = {
projectID: string
workspaceID?: string
directory: string
path?: string
parentID?: string
summary?: {
additions: number
@ -1063,6 +1064,7 @@ export type SyncEventSessionUpdated = {
projectID?: string | null
workspaceID?: string | null
directory?: string | null
path?: string | null
parentID?: string | null
summary?: {
additions: number
@ -1882,6 +1884,7 @@ export type GlobalSession = {
projectID: string
workspaceID?: string
directory: string
path?: string
parentID?: string
summary?: {
additions: number

View file

@ -10154,6 +10154,9 @@
"directory": {
"type": "string"
},
"path": {
"type": "string"
},
"parentID": {
"type": "string",
"pattern": "^ses.*"
@ -10584,6 +10587,16 @@
}
]
},
"path": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"parentID": {
"anyOf": [
{
@ -12538,6 +12551,9 @@
"directory": {
"type": "string"
},
"path": {
"type": "string"
},
"parentID": {
"type": "string",
"pattern": "^ses.*"