bertrand 0.25.1 → 0.27.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 +25 -14
- package/dist/dashboard/assets/index-C5cug9yJ.js +696 -0
- package/dist/dashboard/assets/index-fpXRi6i0.css +1 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/run-screen.js +8 -8
- package/package.json +1 -1
- package/dist/dashboard/assets/index-DVv_2taj.js +0 -696
- package/dist/dashboard/assets/index-ldnBrPCg.css +0 -1
package/dist/bertrand.js
CHANGED
|
@@ -681,7 +681,7 @@ var init_schema = __esm(() => {
|
|
|
681
681
|
slug: text("slug").notNull(),
|
|
682
682
|
name: text("name").notNull(),
|
|
683
683
|
status: text("status", {
|
|
684
|
-
enum: ["active", "waiting", "paused", "archived"]
|
|
684
|
+
enum: ["active", "waiting", "blocked", "paused", "archived"]
|
|
685
685
|
}).notNull().default("paused"),
|
|
686
686
|
summary: text("summary"),
|
|
687
687
|
rating: integer("rating"),
|
|
@@ -890,7 +890,7 @@ var init_parse_session_name = __esm(() => {
|
|
|
890
890
|
});
|
|
891
891
|
|
|
892
892
|
// src/db/queries/sessions.ts
|
|
893
|
-
import { eq as eq2, and, inArray, sql as sql2 } from "drizzle-orm";
|
|
893
|
+
import { eq as eq2, and, inArray, sql as sql2, desc } from "drizzle-orm";
|
|
894
894
|
function resolveSessionByName(name) {
|
|
895
895
|
const flat = parseSessionName(name);
|
|
896
896
|
const flatCategory = getCategoryByPath(flat.categoryPath);
|
|
@@ -942,9 +942,9 @@ function selectSessions(db, opts) {
|
|
|
942
942
|
"active",
|
|
943
943
|
"waiting",
|
|
944
944
|
"paused"
|
|
945
|
-
])).all();
|
|
945
|
+
])).orderBy(desc(sessions.updatedAt)).all();
|
|
946
946
|
}
|
|
947
|
-
return query.all();
|
|
947
|
+
return query.orderBy(desc(sessions.updatedAt)).all();
|
|
948
948
|
}
|
|
949
949
|
function getAllSessions(opts) {
|
|
950
950
|
return selectSessions(getDb(), opts);
|
|
@@ -973,7 +973,7 @@ var init_sessions = __esm(() => {
|
|
|
973
973
|
});
|
|
974
974
|
|
|
975
975
|
// src/db/queries/conversations.ts
|
|
976
|
-
import { eq as eq3, and as and2, desc, sql as sql3 } from "drizzle-orm";
|
|
976
|
+
import { eq as eq3, and as and2, desc as desc2, sql as sql3 } from "drizzle-orm";
|
|
977
977
|
function createConversation(opts) {
|
|
978
978
|
return getDb().insert(conversations).values(opts).returning().get();
|
|
979
979
|
}
|
|
@@ -981,7 +981,7 @@ function getConversation(id) {
|
|
|
981
981
|
return getDb().select().from(conversations).where(eq3(conversations.id, id)).get();
|
|
982
982
|
}
|
|
983
983
|
function getConversationsBySession(sessionId) {
|
|
984
|
-
return getDb().select().from(conversations).where(and2(eq3(conversations.sessionId, sessionId), eq3(conversations.discarded, false))).orderBy(
|
|
984
|
+
return getDb().select().from(conversations).where(and2(eq3(conversations.sessionId, sessionId), eq3(conversations.discarded, false))).orderBy(desc2(conversations.startedAt)).all();
|
|
985
985
|
}
|
|
986
986
|
function endConversation(id) {
|
|
987
987
|
return getDb().update(conversations).set({ endedAt: sql3`(datetime('now'))` }).where(eq3(conversations.id, id)).returning().get();
|
|
@@ -1038,7 +1038,7 @@ function normalizeAnsweredMeta(meta) {
|
|
|
1038
1038
|
}
|
|
1039
1039
|
|
|
1040
1040
|
// src/db/queries/events.ts
|
|
1041
|
-
import { eq as eq4, and as and3, desc as
|
|
1041
|
+
import { eq as eq4, and as and3, desc as desc3 } from "drizzle-orm";
|
|
1042
1042
|
function insertEvent(opts) {
|
|
1043
1043
|
return getDb().insert(events).values({
|
|
1044
1044
|
sessionId: opts.sessionId,
|
|
@@ -1062,7 +1062,7 @@ function getLatestEventOfType(sessionId, eventType, conversationId) {
|
|
|
1062
1062
|
if (conversationId) {
|
|
1063
1063
|
conditions.push(eq4(events.conversationId, conversationId));
|
|
1064
1064
|
}
|
|
1065
|
-
return getDb().select().from(events).where(and3(...conditions)).orderBy(
|
|
1065
|
+
return getDb().select().from(events).where(and3(...conditions)).orderBy(desc3(events.createdAt)).limit(1).get();
|
|
1066
1066
|
}
|
|
1067
1067
|
var init_events = __esm(() => {
|
|
1068
1068
|
init_client();
|
|
@@ -1216,7 +1216,7 @@ __export(exports_update, {
|
|
|
1216
1216
|
function shouldIgnoreStatusFlip(newStatus, sessionPid) {
|
|
1217
1217
|
if (!newStatus)
|
|
1218
1218
|
return false;
|
|
1219
|
-
if (newStatus !== "active" && newStatus !== "waiting")
|
|
1219
|
+
if (newStatus !== "active" && newStatus !== "waiting" && newStatus !== "blocked")
|
|
1220
1220
|
return false;
|
|
1221
1221
|
return sessionPid === null;
|
|
1222
1222
|
}
|
|
@@ -1291,7 +1291,9 @@ var init_update = __esm(() => {
|
|
|
1291
1291
|
init_emit();
|
|
1292
1292
|
EVENT_STATUS_MAP = {
|
|
1293
1293
|
"session.waiting": "waiting",
|
|
1294
|
+
"session.blocked": "blocked",
|
|
1294
1295
|
"session.answered": "active",
|
|
1296
|
+
"session.active": "active",
|
|
1295
1297
|
"session.paused": "paused"
|
|
1296
1298
|
};
|
|
1297
1299
|
register("update", async (args) => {
|
|
@@ -2015,7 +2017,7 @@ function archiveAllPaused() {
|
|
|
2015
2017
|
var ACTIVE_STATUSES;
|
|
2016
2018
|
var init_session_archive = __esm(() => {
|
|
2017
2019
|
init_sessions();
|
|
2018
|
-
ACTIVE_STATUSES = ["active", "waiting"];
|
|
2020
|
+
ACTIVE_STATUSES = ["active", "waiting", "blocked"];
|
|
2019
2021
|
});
|
|
2020
2022
|
|
|
2021
2023
|
// src/server/index.ts
|
|
@@ -2199,7 +2201,7 @@ var PORT, listSessions = (_params, url) => {
|
|
|
2199
2201
|
for (const project of resolveProjectScope(url)) {
|
|
2200
2202
|
const db = getDbForProject(project.slug);
|
|
2201
2203
|
for (const { session } of getAllSessionsForProject(project)) {
|
|
2202
|
-
const isLive = session.status === "active" || session.status === "waiting";
|
|
2204
|
+
const isLive = session.status === "active" || session.status === "waiting" || session.status === "blocked";
|
|
2203
2205
|
if (isLive) {
|
|
2204
2206
|
result[session.id] = liveStats(session.id, db);
|
|
2205
2207
|
continue;
|
|
@@ -2213,7 +2215,7 @@ var PORT, listSessions = (_params, url) => {
|
|
|
2213
2215
|
const session = getSession(sessionId, db);
|
|
2214
2216
|
if (!session)
|
|
2215
2217
|
return null;
|
|
2216
|
-
const isLive = session.status === "active" || session.status === "waiting";
|
|
2218
|
+
const isLive = session.status === "active" || session.status === "waiting" || session.status === "blocked";
|
|
2217
2219
|
if (isLive)
|
|
2218
2220
|
return liveStats(sessionId, db);
|
|
2219
2221
|
return getSessionStats(sessionId, db) ?? liveStats(sessionId, db);
|
|
@@ -3702,6 +3704,12 @@ ${EXTRACT_TOOL}
|
|
|
3702
3704
|
# would look identical to an auto-approved one.
|
|
3703
3705
|
touch "${runtimeDir2}/perm-pending-$sid"
|
|
3704
3706
|
|
|
3707
|
+
# Flip the session to \`blocked\` so the sidebar shows the distinct
|
|
3708
|
+
# permission-request state (orange) instead of looking like Claude is still
|
|
3709
|
+
# working. on-permission-done.sh flips it back to active once the approved
|
|
3710
|
+
# tool runs.
|
|
3711
|
+
bq update --session-id "$sid" --event session.blocked
|
|
3712
|
+
|
|
3705
3713
|
# Badge + notify in background
|
|
3706
3714
|
bq badge bell-exclamation --color '#ff6b35' --priority 25 --beep &
|
|
3707
3715
|
bq notify bertrand "Needs permission: $tool" &
|
|
@@ -3738,6 +3746,9 @@ if [ -f "$marker" ]; then
|
|
|
3738
3746
|
had_marker=1
|
|
3739
3747
|
rm -f "$marker"
|
|
3740
3748
|
bq badge --clear &
|
|
3749
|
+
# Approved tool is now running \u2192 clear the blocked state back to active.
|
|
3750
|
+
# No-op if the session already moved on (update dedupes same-status flips).
|
|
3751
|
+
bq update --session-id "$sid" --event session.active &
|
|
3741
3752
|
fi
|
|
3742
3753
|
|
|
3743
3754
|
cid="\${BERTRAND_CLAUDE_ID:-}"
|
|
@@ -4796,7 +4807,7 @@ var init_stats2 = __esm(() => {
|
|
|
4796
4807
|
init_events();
|
|
4797
4808
|
init_timing();
|
|
4798
4809
|
init_format();
|
|
4799
|
-
ACTIVE_STATUSES2 = ["active", "waiting"];
|
|
4810
|
+
ACTIVE_STATUSES2 = ["active", "waiting", "blocked"];
|
|
4800
4811
|
register("stats", async (args) => {
|
|
4801
4812
|
const isJson = args.includes("--json");
|
|
4802
4813
|
const filteredArgs = args.filter((a) => !a.startsWith("--"));
|
|
@@ -4941,7 +4952,7 @@ function countSessions(slug) {
|
|
|
4941
4952
|
const all = db.select({ status: sessions.status }).from(sessions).all();
|
|
4942
4953
|
return {
|
|
4943
4954
|
total: all.length,
|
|
4944
|
-
active: all.filter((s) => s.status === "active" || s.status === "waiting").length
|
|
4955
|
+
active: all.filter((s) => s.status === "active" || s.status === "waiting" || s.status === "blocked").length
|
|
4945
4956
|
};
|
|
4946
4957
|
} catch {
|
|
4947
4958
|
return UNREADABLE_COUNTS;
|