bertrand 0.22.2 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bertrand.js +514 -287
- package/dist/dashboard/assets/{index-CCHVGoKS.js → index-DW_dgQQt.js} +97 -92
- package/dist/dashboard/index.html +1 -1
- package/dist/migrations/0007_awesome_justin_hammer.sql +2 -0
- package/dist/migrations/meta/0007_snapshot.json +693 -0
- package/dist/migrations/meta/_journal.json +7 -0
- package/dist/run-screen.js +33 -28
- package/package.json +1 -1
package/dist/run-screen.js
CHANGED
|
@@ -561,7 +561,7 @@ function StatusDot({ status }) {
|
|
|
561
561
|
}, undefined, false, undefined, this);
|
|
562
562
|
}
|
|
563
563
|
// src/db/queries/sessions.ts
|
|
564
|
-
import { eq, and, inArray, sql as sql2 } from "drizzle-orm";
|
|
564
|
+
import { eq as eq2, and, inArray, sql as sql2 } from "drizzle-orm";
|
|
565
565
|
|
|
566
566
|
// src/db/client.ts
|
|
567
567
|
import { Database } from "bun:sqlite";
|
|
@@ -763,6 +763,8 @@ var sessions = sqliteTable("sessions", {
|
|
|
763
763
|
pid: integer("pid"),
|
|
764
764
|
startedAt: text("started_at").notNull().default(sql`(datetime('now'))`),
|
|
765
765
|
endedAt: text("ended_at"),
|
|
766
|
+
worktreePath: text("worktree_path"),
|
|
767
|
+
worktreeBranch: text("worktree_branch"),
|
|
766
768
|
createdAt: text("created_at").notNull().default(sql`(datetime('now'))`),
|
|
767
769
|
updatedAt: text("updated_at").notNull().default(sql`(datetime('now'))`)
|
|
768
770
|
}, (t) => [
|
|
@@ -866,13 +868,37 @@ function hasSessionsTable(sqlite) {
|
|
|
866
868
|
// src/lib/id.ts
|
|
867
869
|
import { nanoid } from "nanoid";
|
|
868
870
|
|
|
871
|
+
// src/db/queries/categories.ts
|
|
872
|
+
import { eq, like, or, isNull } from "drizzle-orm";
|
|
873
|
+
|
|
874
|
+
// src/lib/parse-session-name.ts
|
|
875
|
+
var SEGMENT_PATTERN = /^[a-z0-9][a-z0-9._-]*$/i;
|
|
876
|
+
function parseSessionName(input) {
|
|
877
|
+
const trimmed = input.trim().replace(/^\/+|\/+$/g, "");
|
|
878
|
+
if (!trimmed) {
|
|
879
|
+
throw new Error("Session name cannot be empty");
|
|
880
|
+
}
|
|
881
|
+
const segments = trimmed.split("/").filter(Boolean);
|
|
882
|
+
if (segments.length < 2) {
|
|
883
|
+
throw new Error(`Session name must include at least one category: "category/session" (got "${trimmed}")`);
|
|
884
|
+
}
|
|
885
|
+
for (const segment of segments) {
|
|
886
|
+
if (!SEGMENT_PATTERN.test(segment)) {
|
|
887
|
+
throw new Error(`Invalid segment "${segment}": must start with alphanumeric and contain only letters, digits, dots, underscores, or dashes`);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
const categoryPath = segments[0];
|
|
891
|
+
const slug = segments.slice(1).join("/");
|
|
892
|
+
return { categoryPath, slug };
|
|
893
|
+
}
|
|
894
|
+
|
|
869
895
|
// src/db/queries/sessions.ts
|
|
870
896
|
function getSession(id) {
|
|
871
|
-
return getDb().select().from(sessions).where(
|
|
897
|
+
return getDb().select().from(sessions).where(eq2(sessions.id, id)).get();
|
|
872
898
|
}
|
|
873
899
|
function getAllSessions(opts) {
|
|
874
900
|
const db = getDb();
|
|
875
|
-
const query = db.select({ session: sessions, categoryPath: categories.path }).from(sessions).innerJoin(categories,
|
|
901
|
+
const query = db.select({ session: sessions, categoryPath: categories.path }).from(sessions).innerJoin(categories, eq2(sessions.categoryId, categories.id));
|
|
876
902
|
if (opts?.excludeArchived) {
|
|
877
903
|
return query.where(inArray(sessions.status, [
|
|
878
904
|
"active",
|
|
@@ -883,10 +909,10 @@ function getAllSessions(opts) {
|
|
|
883
909
|
return query.all();
|
|
884
910
|
}
|
|
885
911
|
function updateSessionStatus(id, status) {
|
|
886
|
-
return getDb().update(sessions).set({ status, updatedAt: sql2`(datetime('now'))` }).where(
|
|
912
|
+
return getDb().update(sessions).set({ status, updatedAt: sql2`(datetime('now'))` }).where(eq2(sessions.id, id)).returning().get();
|
|
887
913
|
}
|
|
888
914
|
function setSessionRating(id, rating) {
|
|
889
|
-
return getDb().update(sessions).set({ rating, updatedAt: sql2`(datetime('now'))` }).where(
|
|
915
|
+
return getDb().update(sessions).set({ rating, updatedAt: sql2`(datetime('now'))` }).where(eq2(sessions.id, id)).returning().get();
|
|
890
916
|
}
|
|
891
917
|
|
|
892
918
|
// src/lib/session-archive.ts
|
|
@@ -948,27 +974,6 @@ function formatAgo(isoOrDate) {
|
|
|
948
974
|
return date.toLocaleDateString("en-US", { month: "short", day: "numeric" });
|
|
949
975
|
}
|
|
950
976
|
|
|
951
|
-
// src/lib/parse-session-name.ts
|
|
952
|
-
var SEGMENT_PATTERN = /^[a-z0-9][a-z0-9._-]*$/i;
|
|
953
|
-
function parseSessionName(input) {
|
|
954
|
-
const trimmed = input.trim().replace(/^\/+|\/+$/g, "");
|
|
955
|
-
if (!trimmed) {
|
|
956
|
-
throw new Error("Session name cannot be empty");
|
|
957
|
-
}
|
|
958
|
-
const segments = trimmed.split("/").filter(Boolean);
|
|
959
|
-
if (segments.length < 2) {
|
|
960
|
-
throw new Error(`Session name must include at least one category: "category/session" (got "${trimmed}")`);
|
|
961
|
-
}
|
|
962
|
-
for (const segment of segments) {
|
|
963
|
-
if (!SEGMENT_PATTERN.test(segment)) {
|
|
964
|
-
throw new Error(`Invalid segment "${segment}": must start with alphanumeric and contain only letters, digits, dots, underscores, or dashes`);
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
const categoryPath = segments[0];
|
|
968
|
-
const slug = segments.slice(1).join("/");
|
|
969
|
-
return { categoryPath, slug };
|
|
970
|
-
}
|
|
971
|
-
|
|
972
977
|
// src/tui/screens/launch/index.tsx
|
|
973
978
|
import { jsxDEV as jsxDEV6, Fragment } from "react/jsx-dev-runtime";
|
|
974
979
|
var STATUS_COLOR = {
|
|
@@ -1293,9 +1298,9 @@ import { useState as useState4 } from "react";
|
|
|
1293
1298
|
import { Box as Box6, Text as Text7, useInput as useInput3, useTui as useTui2 } from "@orchetron/storm";
|
|
1294
1299
|
|
|
1295
1300
|
// src/db/queries/conversations.ts
|
|
1296
|
-
import { eq as
|
|
1301
|
+
import { eq as eq3, and as and2, desc, sql as sql3 } from "drizzle-orm";
|
|
1297
1302
|
function getConversationsBySession(sessionId) {
|
|
1298
|
-
return getDb().select().from(conversations).where(and2(
|
|
1303
|
+
return getDb().select().from(conversations).where(and2(eq3(conversations.sessionId, sessionId), eq3(conversations.discarded, false))).orderBy(desc(conversations.startedAt)).all();
|
|
1299
1304
|
}
|
|
1300
1305
|
|
|
1301
1306
|
// src/tui/screens/Exit.tsx
|