agent-board-runner 0.1.18 → 0.1.20
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/cli.js +35 -3
- package/dist/index.js +35 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -320,7 +320,7 @@ var BOX_DRAWING_PATTERN = /[─-╿]/g;
|
|
|
320
320
|
var WORKING_PATTERN = /esc to interrupt/i;
|
|
321
321
|
var BACKGROUND_SHELL_PATTERN = /\b[1-9]\d*\s+shells?\b/i;
|
|
322
322
|
function isAgentHookMoment(value) {
|
|
323
|
-
return value === "implementing" || value === "tool_active" || value === "waiting_plan_approval" || value === "waiting_prototype_review" || value === "commit_detected" || value === "turn_stopped" || value === "notification";
|
|
323
|
+
return value === "implementing" || value === "tool_active" || value === "waiting_plan_approval" || value === "waiting_prototype_review" || value === "waiting_workflow_answer" || value === "commit_detected" || value === "turn_stopped" || value === "notification";
|
|
324
324
|
}
|
|
325
325
|
var USAGE_LIMIT_PATTERN = /(usage limit reached|limit reached[^\n]{0,60}resets|reached your (?:usage|session) limit|out of (?:weekly|session) (?:usage|limit))/i;
|
|
326
326
|
var PLAN_APPROVAL_PATTERN = /would you like to proceed\??/i;
|
|
@@ -372,6 +372,8 @@ var AgentActivityWatcher = class {
|
|
|
372
372
|
* "waiting_user" — see the guard in reportHookMoment's "turn_stopped" case.
|
|
373
373
|
*/
|
|
374
374
|
prototypeReviewPending = false;
|
|
375
|
+
/** Same shape as prototypeReviewPending, for ask_workflow_question (see docs/ai-knowledges/workflows-visuais-mecanismo.md). */
|
|
376
|
+
workflowAnswerPending = false;
|
|
375
377
|
toolCallPending = false;
|
|
376
378
|
commitDetected = false;
|
|
377
379
|
timer;
|
|
@@ -414,6 +416,7 @@ var AgentActivityWatcher = class {
|
|
|
414
416
|
this.usageLimited = false;
|
|
415
417
|
this.planApprovalPending = false;
|
|
416
418
|
this.prototypeReviewPending = false;
|
|
419
|
+
this.workflowAnswerPending = false;
|
|
417
420
|
this.commitDetected = false;
|
|
418
421
|
this.setState("implementing");
|
|
419
422
|
break;
|
|
@@ -429,12 +432,17 @@ var AgentActivityWatcher = class {
|
|
|
429
432
|
this.prototypeReviewPending = true;
|
|
430
433
|
this.setState("waiting_prototype_review");
|
|
431
434
|
break;
|
|
435
|
+
case "waiting_workflow_answer":
|
|
436
|
+
this.workflowAnswerPending = true;
|
|
437
|
+
this.setState("waiting_workflow_answer");
|
|
438
|
+
break;
|
|
432
439
|
case "commit_detected":
|
|
433
440
|
this.commitDetected = true;
|
|
434
441
|
break;
|
|
435
442
|
case "turn_stopped":
|
|
436
443
|
if (this.usageLimited) break;
|
|
437
444
|
if (this.prototypeReviewPending) break;
|
|
445
|
+
if (this.workflowAnswerPending) break;
|
|
438
446
|
if (BACKGROUND_SHELL_PATTERN.test(this.recentOutput())) {
|
|
439
447
|
this.setState("waiting_background");
|
|
440
448
|
break;
|
|
@@ -1255,6 +1263,11 @@ function detectMoment(input) {
|
|
|
1255
1263
|
// prototypeReviewPending latch in agentActivity.ts's reportHookMoment.
|
|
1256
1264
|
if (eventName === "PostToolUse" && input.tool_name === "mcp__agent-board__publish_prototype") return "waiting_prototype_review";
|
|
1257
1265
|
|
|
1266
|
+
// Same shape as publish_prototype above, but for a workflow graph's "ask" node (see
|
|
1267
|
+
// ask_workflow_question in boardTools.ts and docs/ai-knowledges/workflows-visuais-mecanismo.md)
|
|
1268
|
+
// \u2014 see the workflowAnswerPending latch in agentActivity.ts's reportHookMoment.
|
|
1269
|
+
if (eventName === "PostToolUse" && input.tool_name === "mcp__agent-board__ask_workflow_question") return "waiting_workflow_answer";
|
|
1270
|
+
|
|
1258
1271
|
// A commit that actually succeeded, read off the Bash tool's own structured result instead
|
|
1259
1272
|
// of guessing from scrollback text (exact, and immune to locale/color/format changes to
|
|
1260
1273
|
// git's own banner). Any other Bash completion still reports "tool_active" below, same as
|
|
@@ -3229,7 +3242,7 @@ async function dispatchRunnerQueue(supabase, config) {
|
|
|
3229
3242
|
for (const project of config.registeredProjects) {
|
|
3230
3243
|
const running = await getRunningSessionForProject(supabase, project.id, config.runnerId);
|
|
3231
3244
|
if (!running) continue;
|
|
3232
|
-
if ((running.agentState === "done" || running.agentState === "waiting_prototype_review") && queuedProjectIds.has(project.id)) {
|
|
3245
|
+
if ((running.agentState === "done" || running.agentState === "waiting_prototype_review" || running.agentState === "waiting_workflow_answer") && queuedProjectIds.has(project.id)) {
|
|
3233
3246
|
await pauseFinishedSession(supabase, config, project.id, running.cardId, running.id);
|
|
3234
3247
|
continue;
|
|
3235
3248
|
}
|
|
@@ -3294,6 +3307,14 @@ async function publishQueueSnapshots(supabase, config, queued, promotedCardIds)
|
|
|
3294
3307
|
function buildPrototypeReviewFollowUp(prototypeApproved, prototypeUrl) {
|
|
3295
3308
|
return prototypeApproved ? "O prot\xF3tipo foi revisado e aprovado \u2014 prossiga para a implementa\xE7\xE3o real, usando-o como refer\xEAncia." : `O prot\xF3tipo ainda n\xE3o foi aprovado${prototypeUrl ? ` (${prototypeUrl})` : ""} \u2014 confira os coment\xE1rios deixados nele (e, se for um prot\xF3tipo de marca\xE7\xE3o de pontos, os pontos salvos) e ajuste, publicando a nova vers\xE3o com publish_prototype. Depois, pare o turno de novo: a sess\xE3o ser\xE1 retomada quando houver outra revis\xE3o.`;
|
|
3296
3309
|
}
|
|
3310
|
+
async function buildWorkflowAnswerFollowUp(supabase, cardId) {
|
|
3311
|
+
const { data } = await supabase.from("card_workflow_questions").select("question, answer").eq("card_id", cardId).eq("status", "answered").order("answered_at", { ascending: false }).limit(1).maybeSingle();
|
|
3312
|
+
if (!data) return "A pergunta foi respondida \u2014 confira os coment\xE1rios do card e prossiga.";
|
|
3313
|
+
return `Pergunta: "${data.question}"
|
|
3314
|
+
Resposta do humano: "${data.answer}"
|
|
3315
|
+
|
|
3316
|
+
Prossiga com o workflow a partir daqui.`;
|
|
3317
|
+
}
|
|
3297
3318
|
async function promoteQueuedSession(supabase, config, entry) {
|
|
3298
3319
|
const existingHandle = getPtySession(entry.id);
|
|
3299
3320
|
if (existingHandle) {
|
|
@@ -3313,6 +3334,9 @@ async function promoteQueuedSession(supabase, config, entry) {
|
|
|
3313
3334
|
buildPrototypeReviewFollowUp(entry.cards.prototype_approved, entry.cards.prototype_url)
|
|
3314
3335
|
);
|
|
3315
3336
|
}
|
|
3337
|
+
if (entry.agent_state === "waiting_workflow_answer" && !existingHandle.exited) {
|
|
3338
|
+
sendMessageToIdleSession(existingHandle.pty, entry.card_id, await buildWorkflowAnswerFollowUp(supabase, entry.card_id));
|
|
3339
|
+
}
|
|
3316
3340
|
return;
|
|
3317
3341
|
}
|
|
3318
3342
|
const spawned = await spawnSessionPty(supabase, config, entry);
|
|
@@ -3431,7 +3455,7 @@ function watchAgentActivity(supabase, config, projectId, cardId, sessionId, pty)
|
|
|
3431
3455
|
} else {
|
|
3432
3456
|
cancelUsageResume(sessionId);
|
|
3433
3457
|
}
|
|
3434
|
-
if (state === "done" || state === "waiting_prototype_review") void dispatchRunnerQueue(supabase, config);
|
|
3458
|
+
if (state === "done" || state === "waiting_prototype_review" || state === "waiting_workflow_answer") void dispatchRunnerQueue(supabase, config);
|
|
3435
3459
|
});
|
|
3436
3460
|
pty.onData((chunk) => watcher.push(chunk));
|
|
3437
3461
|
registerAgentActivityWatcher(sessionId, watcher);
|
|
@@ -3466,6 +3490,14 @@ async function requeuePausedCard(supabase, config, card) {
|
|
|
3466
3490
|
logger.card.info(card.id, `Session ${active.id} was never paused (alone in its project) \u2014 sent the prototype review follow-up directly.`);
|
|
3467
3491
|
}
|
|
3468
3492
|
}
|
|
3493
|
+
if (active.status === "running" && active.agentState === "waiting_workflow_answer") {
|
|
3494
|
+
const handle = getPtySession(active.id);
|
|
3495
|
+
await updateCard(supabase, card.id, { requeueRequestedAt: null });
|
|
3496
|
+
if (handle && !handle.exited) {
|
|
3497
|
+
sendMessageToIdleSession(handle.pty, card.id, await buildWorkflowAnswerFollowUp(supabase, card.id));
|
|
3498
|
+
logger.card.info(card.id, `Session ${active.id} was never paused (alone in its project) \u2014 sent the workflow answer follow-up directly.`);
|
|
3499
|
+
}
|
|
3500
|
+
}
|
|
3469
3501
|
}
|
|
3470
3502
|
async function reconcileOrphanedSessions(supabase, config) {
|
|
3471
3503
|
for (const project of config.registeredProjects) {
|
package/dist/index.js
CHANGED
|
@@ -40,7 +40,7 @@ var BOX_DRAWING_PATTERN = /[─-╿]/g;
|
|
|
40
40
|
var WORKING_PATTERN = /esc to interrupt/i;
|
|
41
41
|
var BACKGROUND_SHELL_PATTERN = /\b[1-9]\d*\s+shells?\b/i;
|
|
42
42
|
function isAgentHookMoment(value) {
|
|
43
|
-
return value === "implementing" || value === "tool_active" || value === "waiting_plan_approval" || value === "waiting_prototype_review" || value === "commit_detected" || value === "turn_stopped" || value === "notification";
|
|
43
|
+
return value === "implementing" || value === "tool_active" || value === "waiting_plan_approval" || value === "waiting_prototype_review" || value === "waiting_workflow_answer" || value === "commit_detected" || value === "turn_stopped" || value === "notification";
|
|
44
44
|
}
|
|
45
45
|
var USAGE_LIMIT_PATTERN = /(usage limit reached|limit reached[^\n]{0,60}resets|reached your (?:usage|session) limit|out of (?:weekly|session) (?:usage|limit))/i;
|
|
46
46
|
var PLAN_APPROVAL_PATTERN = /would you like to proceed\??/i;
|
|
@@ -92,6 +92,8 @@ var AgentActivityWatcher = class {
|
|
|
92
92
|
* "waiting_user" — see the guard in reportHookMoment's "turn_stopped" case.
|
|
93
93
|
*/
|
|
94
94
|
prototypeReviewPending = false;
|
|
95
|
+
/** Same shape as prototypeReviewPending, for ask_workflow_question (see docs/ai-knowledges/workflows-visuais-mecanismo.md). */
|
|
96
|
+
workflowAnswerPending = false;
|
|
95
97
|
toolCallPending = false;
|
|
96
98
|
commitDetected = false;
|
|
97
99
|
timer;
|
|
@@ -134,6 +136,7 @@ var AgentActivityWatcher = class {
|
|
|
134
136
|
this.usageLimited = false;
|
|
135
137
|
this.planApprovalPending = false;
|
|
136
138
|
this.prototypeReviewPending = false;
|
|
139
|
+
this.workflowAnswerPending = false;
|
|
137
140
|
this.commitDetected = false;
|
|
138
141
|
this.setState("implementing");
|
|
139
142
|
break;
|
|
@@ -149,12 +152,17 @@ var AgentActivityWatcher = class {
|
|
|
149
152
|
this.prototypeReviewPending = true;
|
|
150
153
|
this.setState("waiting_prototype_review");
|
|
151
154
|
break;
|
|
155
|
+
case "waiting_workflow_answer":
|
|
156
|
+
this.workflowAnswerPending = true;
|
|
157
|
+
this.setState("waiting_workflow_answer");
|
|
158
|
+
break;
|
|
152
159
|
case "commit_detected":
|
|
153
160
|
this.commitDetected = true;
|
|
154
161
|
break;
|
|
155
162
|
case "turn_stopped":
|
|
156
163
|
if (this.usageLimited) break;
|
|
157
164
|
if (this.prototypeReviewPending) break;
|
|
165
|
+
if (this.workflowAnswerPending) break;
|
|
158
166
|
if (BACKGROUND_SHELL_PATTERN.test(this.recentOutput())) {
|
|
159
167
|
this.setState("waiting_background");
|
|
160
168
|
break;
|
|
@@ -975,6 +983,11 @@ function detectMoment(input) {
|
|
|
975
983
|
// prototypeReviewPending latch in agentActivity.ts's reportHookMoment.
|
|
976
984
|
if (eventName === "PostToolUse" && input.tool_name === "mcp__agent-board__publish_prototype") return "waiting_prototype_review";
|
|
977
985
|
|
|
986
|
+
// Same shape as publish_prototype above, but for a workflow graph's "ask" node (see
|
|
987
|
+
// ask_workflow_question in boardTools.ts and docs/ai-knowledges/workflows-visuais-mecanismo.md)
|
|
988
|
+
// \u2014 see the workflowAnswerPending latch in agentActivity.ts's reportHookMoment.
|
|
989
|
+
if (eventName === "PostToolUse" && input.tool_name === "mcp__agent-board__ask_workflow_question") return "waiting_workflow_answer";
|
|
990
|
+
|
|
978
991
|
// A commit that actually succeeded, read off the Bash tool's own structured result instead
|
|
979
992
|
// of guessing from scrollback text (exact, and immune to locale/color/format changes to
|
|
980
993
|
// git's own banner). Any other Bash completion still reports "tool_active" below, same as
|
|
@@ -3117,7 +3130,7 @@ async function dispatchRunnerQueue(supabase, config) {
|
|
|
3117
3130
|
for (const project of config.registeredProjects) {
|
|
3118
3131
|
const running = await getRunningSessionForProject(supabase, project.id, config.runnerId);
|
|
3119
3132
|
if (!running) continue;
|
|
3120
|
-
if ((running.agentState === "done" || running.agentState === "waiting_prototype_review") && queuedProjectIds.has(project.id)) {
|
|
3133
|
+
if ((running.agentState === "done" || running.agentState === "waiting_prototype_review" || running.agentState === "waiting_workflow_answer") && queuedProjectIds.has(project.id)) {
|
|
3121
3134
|
await pauseFinishedSession(supabase, config, project.id, running.cardId, running.id);
|
|
3122
3135
|
continue;
|
|
3123
3136
|
}
|
|
@@ -3182,6 +3195,14 @@ async function publishQueueSnapshots(supabase, config, queued, promotedCardIds)
|
|
|
3182
3195
|
function buildPrototypeReviewFollowUp(prototypeApproved, prototypeUrl) {
|
|
3183
3196
|
return prototypeApproved ? "O prot\xF3tipo foi revisado e aprovado \u2014 prossiga para a implementa\xE7\xE3o real, usando-o como refer\xEAncia." : `O prot\xF3tipo ainda n\xE3o foi aprovado${prototypeUrl ? ` (${prototypeUrl})` : ""} \u2014 confira os coment\xE1rios deixados nele (e, se for um prot\xF3tipo de marca\xE7\xE3o de pontos, os pontos salvos) e ajuste, publicando a nova vers\xE3o com publish_prototype. Depois, pare o turno de novo: a sess\xE3o ser\xE1 retomada quando houver outra revis\xE3o.`;
|
|
3184
3197
|
}
|
|
3198
|
+
async function buildWorkflowAnswerFollowUp(supabase, cardId) {
|
|
3199
|
+
const { data } = await supabase.from("card_workflow_questions").select("question, answer").eq("card_id", cardId).eq("status", "answered").order("answered_at", { ascending: false }).limit(1).maybeSingle();
|
|
3200
|
+
if (!data) return "A pergunta foi respondida \u2014 confira os coment\xE1rios do card e prossiga.";
|
|
3201
|
+
return `Pergunta: "${data.question}"
|
|
3202
|
+
Resposta do humano: "${data.answer}"
|
|
3203
|
+
|
|
3204
|
+
Prossiga com o workflow a partir daqui.`;
|
|
3205
|
+
}
|
|
3185
3206
|
async function promoteQueuedSession(supabase, config, entry) {
|
|
3186
3207
|
const existingHandle = getPtySession(entry.id);
|
|
3187
3208
|
if (existingHandle) {
|
|
@@ -3201,6 +3222,9 @@ async function promoteQueuedSession(supabase, config, entry) {
|
|
|
3201
3222
|
buildPrototypeReviewFollowUp(entry.cards.prototype_approved, entry.cards.prototype_url)
|
|
3202
3223
|
);
|
|
3203
3224
|
}
|
|
3225
|
+
if (entry.agent_state === "waiting_workflow_answer" && !existingHandle.exited) {
|
|
3226
|
+
sendMessageToIdleSession(existingHandle.pty, entry.card_id, await buildWorkflowAnswerFollowUp(supabase, entry.card_id));
|
|
3227
|
+
}
|
|
3204
3228
|
return;
|
|
3205
3229
|
}
|
|
3206
3230
|
const spawned = await spawnSessionPty(supabase, config, entry);
|
|
@@ -3319,7 +3343,7 @@ function watchAgentActivity(supabase, config, projectId, cardId, sessionId, pty)
|
|
|
3319
3343
|
} else {
|
|
3320
3344
|
cancelUsageResume(sessionId);
|
|
3321
3345
|
}
|
|
3322
|
-
if (state === "done" || state === "waiting_prototype_review") void dispatchRunnerQueue(supabase, config);
|
|
3346
|
+
if (state === "done" || state === "waiting_prototype_review" || state === "waiting_workflow_answer") void dispatchRunnerQueue(supabase, config);
|
|
3323
3347
|
});
|
|
3324
3348
|
pty.onData((chunk) => watcher.push(chunk));
|
|
3325
3349
|
registerAgentActivityWatcher(sessionId, watcher);
|
|
@@ -3354,6 +3378,14 @@ async function requeuePausedCard(supabase, config, card) {
|
|
|
3354
3378
|
logger.card.info(card.id, `Session ${active.id} was never paused (alone in its project) \u2014 sent the prototype review follow-up directly.`);
|
|
3355
3379
|
}
|
|
3356
3380
|
}
|
|
3381
|
+
if (active.status === "running" && active.agentState === "waiting_workflow_answer") {
|
|
3382
|
+
const handle = getPtySession(active.id);
|
|
3383
|
+
await updateCard(supabase, card.id, { requeueRequestedAt: null });
|
|
3384
|
+
if (handle && !handle.exited) {
|
|
3385
|
+
sendMessageToIdleSession(handle.pty, card.id, await buildWorkflowAnswerFollowUp(supabase, card.id));
|
|
3386
|
+
logger.card.info(card.id, `Session ${active.id} was never paused (alone in its project) \u2014 sent the workflow answer follow-up directly.`);
|
|
3387
|
+
}
|
|
3388
|
+
}
|
|
3357
3389
|
}
|
|
3358
3390
|
async function reconcileOrphanedSessions(supabase, config) {
|
|
3359
3391
|
for (const project of config.registeredProjects) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-board-runner",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20",
|
|
4
4
|
"description": "Local runner for Agent Board — signs in with your own Supabase account (no shared secrets) and drives Claude Code against repos under your local repos root.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|