@bivy/bivy 0.5.1-staging.64 → 0.5.1-staging.65
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/server.js +31 -3
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -409,13 +409,14 @@ const approvals = new ApprovalManager();
|
|
|
409
409
|
const questionManager = new QuestionManager();
|
|
410
410
|
questionManager.onRequest((request) => {
|
|
411
411
|
scheduleAdvertise();
|
|
412
|
-
broadcast({ type: "session.question", sessionId: request.sessionId, requestId: request.id, questions: request.questions });
|
|
412
|
+
broadcast({ type: "session.question", sessionId: request.sessionId, requestId: request.id, questions: request.questions, createdAt: request.createdAt });
|
|
413
413
|
// Notify unconditionally: a clarifying question always fires mid-turn (the
|
|
414
414
|
// session is "working"), and it's a hard blocker the user must see to unblock
|
|
415
415
|
// — matching the pre-refactor behavior.
|
|
416
416
|
void sendNotificationHint({
|
|
417
417
|
kind: "question_asked",
|
|
418
418
|
sessionId: request.sessionId,
|
|
419
|
+
attentionId: request.id,
|
|
419
420
|
title: "Bivy needs your input",
|
|
420
421
|
body: `${sessionNotifyLabel(resolveSession(request.sessionId))} is asking a question — tap to answer.`,
|
|
421
422
|
});
|
|
@@ -4320,16 +4321,37 @@ async function advertiseSessions() {
|
|
|
4320
4321
|
// dropped; and with the remote flag off the map is empty, so the payload is
|
|
4321
4322
|
// byte-identical to before.
|
|
4322
4323
|
const agentServiceAddress = sessionAgentServiceAddress(record) ?? (record ? undefined : (await inMemorySessionLocations.lookup(s.id).catch(() => undefined))?.agentServiceAddress);
|
|
4324
|
+
const approvalAttention = approvals.list()
|
|
4325
|
+
.filter((a) => a.sessionId === s.id && a.status === "pending")
|
|
4326
|
+
.map((a) => ({
|
|
4327
|
+
id: a.id,
|
|
4328
|
+
kind: "approval",
|
|
4329
|
+
severity: a.risk === "critical" ? "critical" : a.risk === "high" ? "error" : "warning",
|
|
4330
|
+
createdAt: new Date(a.createdAt).toISOString(),
|
|
4331
|
+
}));
|
|
4332
|
+
const questionAttention = questionManager.list()
|
|
4333
|
+
.filter((q) => q.sessionId === s.id && q.status === "pending")
|
|
4334
|
+
.map((q) => ({ id: q.id, kind: "question", severity: "warning", createdAt: new Date(q.createdAt).toISOString() }));
|
|
4335
|
+
const failureAt = record?.lastFailureAt || (meta?.status === "failed" ? Date.parse(meta.updatedAt) : 0);
|
|
4336
|
+
const failureAttention = failureAt
|
|
4337
|
+
? [{
|
|
4338
|
+
id: "last-failure",
|
|
4339
|
+
kind: (record?.source || meta?.source ? "automation" : "session"),
|
|
4340
|
+
severity: "error",
|
|
4341
|
+
createdAt: new Date(failureAt).toISOString(),
|
|
4342
|
+
}]
|
|
4343
|
+
: [];
|
|
4323
4344
|
return {
|
|
4324
4345
|
sessionId: s.id,
|
|
4325
|
-
status: pendingApproval ? "needs_action" : (record ? (sessionBusy(record) ? "working" : "idle") : "saved"),
|
|
4326
|
-
needsAction: pendingApproval,
|
|
4346
|
+
status: pendingApproval || failureAttention.length ? "needs_action" : (record ? (sessionBusy(record) ? "working" : "idle") : "saved"),
|
|
4347
|
+
needsAction: pendingApproval || failureAttention.length > 0,
|
|
4327
4348
|
source: record?.source || meta?.source,
|
|
4328
4349
|
titleEnc: name ? relay.sealString(name) : undefined,
|
|
4329
4350
|
branch: record?.worktree?.branch || meta?.branch,
|
|
4330
4351
|
agentServiceAddress,
|
|
4331
4352
|
githubIssueUrl: record?.githubIssueUrl,
|
|
4332
4353
|
prUrl: record?.prUrl,
|
|
4354
|
+
attention: [...approvalAttention, ...questionAttention, ...failureAttention],
|
|
4333
4355
|
};
|
|
4334
4356
|
}));
|
|
4335
4357
|
try {
|
|
@@ -6612,6 +6634,8 @@ function markSessionWorking(record, activity) {
|
|
|
6612
6634
|
record.isWorking = true;
|
|
6613
6635
|
record.lastActivity = activity;
|
|
6614
6636
|
record.workingStartedAt ||= Date.now();
|
|
6637
|
+
// A new attempt resolves the prior turn's failure condition at its source.
|
|
6638
|
+
record.lastFailureAt = undefined;
|
|
6615
6639
|
metadata.touchSession(record.id, "working");
|
|
6616
6640
|
if (!wasWorking)
|
|
6617
6641
|
scheduleAdvertise(); // idle → working transition
|
|
@@ -6823,6 +6847,9 @@ function attachSessionListeners(record) {
|
|
|
6823
6847
|
});
|
|
6824
6848
|
}
|
|
6825
6849
|
else if (turnError) {
|
|
6850
|
+
record.lastFailureAt = Date.now();
|
|
6851
|
+
metadata.touchSession(record.id, "failed");
|
|
6852
|
+
scheduleAdvertise();
|
|
6826
6853
|
broadcast({ type: "session.error", sessionId: record.id, error: turnError });
|
|
6827
6854
|
void sendNotificationHint({
|
|
6828
6855
|
kind: "session_error",
|
|
@@ -7983,6 +8010,7 @@ approvals.onRequest((request) => {
|
|
|
7983
8010
|
void sendNotificationHint({
|
|
7984
8011
|
kind: "approval_requested",
|
|
7985
8012
|
sessionId: request.sessionId,
|
|
8013
|
+
attentionId: request.id,
|
|
7986
8014
|
title: "Approval needed",
|
|
7987
8015
|
body: `${sessionNotifyLabel(rec)} wants to run something — tap to approve or deny.`,
|
|
7988
8016
|
});
|
package/package.json
CHANGED