Repository navigation
fix(web): deleting a thread with side chats offers to delete its worktree #29792
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e58ad1d
779063d
38370c6
a148a18
519f44a
d7cc758
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -93,6 +93,7 @@ import * as SqlClient from "effect/sql/SqlClient"; | |
| import type * as Statement from "effect/sql/Statement"; | ||
|
|
||
| import { MCP_APP_OUTPUT_KEY } from "@t3tools/shared/mcpApp"; | ||
| import { normalizeProjectPathForComparison } from "@t3tools/shared/path"; | ||
| import { threadHtmlRenderAttachmentIds } from "../attachmentStore.ts"; | ||
| import { readableSearchText } from "./messageSearchIndex.ts"; | ||
| import { | ||
|
|
@@ -1097,6 +1098,7 @@ type ShellThreadRow = { | |
| readonly thread_id: string; | ||
| readonly payload_json: string; | ||
| readonly forked_from_run_source_thread_id: string | null; | ||
| readonly worktree_path: string | null; | ||
| readonly latest_run_id: string | null; | ||
| readonly latest_run_status: string | null; | ||
| readonly latest_run_requested_at: string | null; | ||
|
|
@@ -7663,6 +7665,7 @@ export const layer: Layer.Layer<ProjectionStoreV2, never, SqlClient.SqlClient> = | |
| THEN json_extract(t.payload_json, '$.forkedFrom.threadId') | ||
| ELSE NULL | ||
| END AS forked_from_run_source_thread_id, | ||
| json_extract(t.payload_json, '$.worktreePath') AS worktree_path, | ||
| presented.run_id AS latest_run_id, | ||
| presented.status AS latest_run_status, | ||
| presented.requested_at AS latest_run_requested_at, | ||
|
|
@@ -7859,8 +7862,20 @@ export const layer: Layer.Layer<ProjectionStoreV2, never, SqlClient.SqlClient> = | |
| }${ | ||
| worktreePath === undefined | ||
| ? sql`` | ||
| : sql` AND CASE WHEN json_valid(t.payload_json) | ||
| THEN json_extract(t.payload_json, '$.worktreePath') END = ${worktreePath}` | ||
| : // The key matches orchestration_v2_projection_threads_worktree_path_key_idx, so an | ||
| // ASCII path does not scan the table. SQLite lower() folds only ASCII, so a query | ||
| // that itself contains another character also admits those stored paths; | ||
| // readShellSnapshotRows keeps the exact comparison. | ||
| sql` AND (CASE WHEN json_valid(t.payload_json) | ||
| THEN lower(rtrim(replace(trim(json_extract(t.payload_json, '$.worktreePath')), '\\', '/'), '/')) | ||
| END = lower(rtrim(replace(trim(${worktreePath}), '\\', '/'), '/'))${ | ||
| /^[\u0000-\u007e]*$/u.test(worktreePath) | ||
| ? sql`` | ||
| : sql` OR ( | ||
|
Comment on lines
+7872
to
+7874
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Keep Unicode candidates when the requested path is ASCII. If the stored Windows path is Make candidate selection include stored Unicode paths that can normalize to an ASCII key. Extend the existing Windows case with an ASCII query against this stored path.
|
||
| json_valid(t.payload_json) | ||
| AND json_extract(t.payload_json, '$.worktreePath') GLOB '*[^ -~]*' | ||
| )` | ||
| })` | ||
| }${threadIds === undefined ? sql`` : sql` AND t.thread_id IN (SELECT value FROM json_each(${encodeIdList(threadIds)}))`} | ||
| ORDER BY t.updated_at ASC, t.thread_id ASC | ||
| `; | ||
|
|
@@ -8474,7 +8489,16 @@ export const layer: Layer.Layer<ProjectionStoreV2, never, SqlClient.SqlClient> = | |
| const readShellSnapshotRows = Effect.fn("ProjectionStore.readShellSnapshotRows")(function* ( | ||
| options: ShellSnapshotOptions | undefined, | ||
| ) { | ||
| const targetThreadRows = yield* selectShellThreadRows(undefined, options); | ||
| const worktreeKey = | ||
| options?.worktreePath === undefined | ||
| ? undefined | ||
| : normalizeProjectPathForComparison(options.worktreePath); | ||
| const targetThreadRows = (yield* selectShellThreadRows(undefined, options)).filter( | ||
| (row) => | ||
| worktreeKey === undefined || | ||
| (row.worktree_path !== null && | ||
| normalizeProjectPathForComparison(row.worktree_path) === worktreeKey), | ||
|
saphid marked this conversation as resolved.
Resolved
|
||
| ); | ||
| const targetThreadIds = new Set(targetThreadRows.map((row) => ThreadId.make(row.thread_id))); | ||
| const rowsByThreadId = new Map( | ||
| targetThreadRows.map((row) => [ThreadId.make(row.thread_id), row] as const), | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import * as Effect from "effect/Effect"; | ||
| import * as SqlClient from "effect/sql/SqlClient"; | ||
|
|
||
| export default Effect.gen(function* () { | ||
| const sql = yield* SqlClient.SqlClient; | ||
|
|
||
| // Keep this expression identical to ProjectionStore's loose worktree filter. | ||
| yield* sql` | ||
| CREATE INDEX IF NOT EXISTS orchestration_v2_projection_threads_worktree_path_key_idx | ||
| ON orchestration_v2_projection_threads( | ||
| CASE WHEN json_valid(payload_json) | ||
| THEN lower(rtrim(replace(trim(json_extract(payload_json, '$.worktreePath')), '\\', '/'), '/')) | ||
| END | ||
| ) | ||
| `; | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Match JavaScript whitespace trimming in the SQL filter.
If the stored path is
/repo/wtand the requested path is"\t/repo/wt\n", the shared helper produces equal keys. SQLite's one-argumenttrim()removes spaces, not tabs or newlines. The SQL filter therefore excludes the thread before the exact comparison can run. The ASCII query also skips the fallback. (sqlite.org)Use the JavaScript whitespace set for both SQL operands and the matching index expression in
092_WorktreePathKeyIndex.ts, Line 12. Extend the existing path-filter test with this case.