@exaudeus/workrail 3.33.0 → 3.34.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/cli-worktrain.js +167 -8
- package/dist/console-ui/assets/{index-BuJFLLfY.js → index-C1JXnwZS.js} +1 -1
- package/dist/console-ui/index.html +1 -1
- package/dist/daemon/agent-loop.d.ts +1 -0
- package/dist/daemon/agent-loop.js +1 -1
- package/dist/daemon/daemon-events.d.ts +17 -1
- package/dist/daemon/workflow-runner.d.ts +1 -1
- package/dist/daemon/workflow-runner.js +96 -21
- package/dist/manifest.json +43 -67
- package/dist/mcp/handlers/v2-error-mapping.d.ts +3 -0
- package/dist/mcp/handlers/v2-error-mapping.js +2 -0
- package/dist/mcp/handlers/v2-execution/advance.js +25 -0
- package/dist/mcp/handlers/v2-execution/continue-advance.js +7 -0
- package/dist/mcp/transports/http-entry.js +0 -7
- package/dist/mcp/transports/stdio-entry.js +0 -8
- package/dist/mcp-server.d.ts +0 -2
- package/dist/mcp-server.js +1 -42
- package/dist/v2/durable-core/domain/observation-builder.d.ts +3 -0
- package/dist/v2/durable-core/domain/observation-builder.js +2 -2
- package/dist/v2/durable-core/domain/prompt-renderer.d.ts +2 -1
- package/dist/v2/durable-core/domain/prompt-renderer.js +10 -0
- package/dist/v2/usecases/console-service.js +65 -14
- package/dist/v2/usecases/console-types.d.ts +1 -0
- package/docs/design/bridge-removal-pr-a-candidates.md +115 -0
- package/docs/design/bridge-removal-pr-a-design-review.md +79 -0
- package/docs/design/bridge-removal-pr-a-implementation-plan.md +203 -0
- package/docs/discovery/design-candidates.md +180 -0
- package/docs/discovery/design-review-findings.md +110 -0
- package/docs/discovery/wr-discovery-goal-reframing.md +303 -0
- package/docs/ideas/backlog.md +266 -0
- package/package.json +1 -1
- package/workflows/wr.discovery.json +58 -7
- package/dist/mcp/transports/bridge-entry.d.ts +0 -102
- package/dist/mcp/transports/bridge-entry.js +0 -454
- package/dist/mcp/transports/bridge-events.d.ts +0 -55
- package/dist/mcp/transports/bridge-events.js +0 -24
- package/dist/mcp/transports/primary-tombstone.d.ts +0 -21
- package/dist/mcp/transports/primary-tombstone.js +0 -51
package/dist/cli-worktrain.js
CHANGED
|
@@ -377,6 +377,8 @@ function formatDaemonEventLine(raw) {
|
|
|
377
377
|
const sessionId = typeof obj['sessionId'] === 'string' ? obj['sessionId'].slice(0, 8) : null;
|
|
378
378
|
const prefix = sessionId ? `[${ts}] [${sessionId}] ${kind}` : `[${ts}] ${kind}`;
|
|
379
379
|
switch (kind) {
|
|
380
|
+
case 'agent_stuck':
|
|
381
|
+
return `${prefix} *** STUCK: ${obj['reason'] ?? '?'} -- ${String(obj['detail'] ?? '').slice(0, 100)}`;
|
|
380
382
|
case 'llm_turn_started':
|
|
381
383
|
return `${prefix} msgs=${obj['messageCount'] ?? '?'}`;
|
|
382
384
|
case 'llm_turn_completed':
|
|
@@ -393,12 +395,33 @@ function formatDaemonEventLine(raw) {
|
|
|
393
395
|
return `${prefix} tool=${obj['toolName'] ?? '?'} err=${String(obj['error'] ?? '').slice(0, 80)}`;
|
|
394
396
|
case 'session_started':
|
|
395
397
|
return `${prefix} workflow=${obj['workflowId'] ?? '?'} workspace=${obj['workspacePath'] ?? '?'}`;
|
|
396
|
-
case 'session_completed':
|
|
397
|
-
|
|
398
|
+
case 'session_completed': {
|
|
399
|
+
const outcome = obj['outcome'];
|
|
400
|
+
const detail = obj['detail'] ? ` (${obj['detail']})` : '';
|
|
401
|
+
if (outcome === 'success') {
|
|
402
|
+
return `${prefix} workflow=${obj['workflowId'] ?? '?'} -- session complete${detail}`;
|
|
403
|
+
}
|
|
404
|
+
else if (outcome === 'error') {
|
|
405
|
+
return `${prefix} workflow=${obj['workflowId'] ?? '?'} -- session FAILED${detail}`;
|
|
406
|
+
}
|
|
407
|
+
else if (outcome === 'timeout') {
|
|
408
|
+
return `${prefix} workflow=${obj['workflowId'] ?? '?'} -- session TIMEOUT${detail}`;
|
|
409
|
+
}
|
|
410
|
+
return `${prefix} workflow=${obj['workflowId'] ?? '?'} outcome=${outcome ?? '?'}${detail}`;
|
|
411
|
+
}
|
|
398
412
|
case 'step_advanced':
|
|
399
|
-
return `${prefix}`;
|
|
400
|
-
case 'issue_reported':
|
|
401
|
-
|
|
413
|
+
return `${prefix} -> step advanced`;
|
|
414
|
+
case 'issue_reported': {
|
|
415
|
+
const severity = obj['severity'];
|
|
416
|
+
const summary = String(obj['summary'] ?? '').slice(0, 100);
|
|
417
|
+
if (severity === 'fatal') {
|
|
418
|
+
return `${prefix} FATAL: ${summary}`;
|
|
419
|
+
}
|
|
420
|
+
else if (severity === 'error') {
|
|
421
|
+
return `${prefix} ERROR: ${summary}`;
|
|
422
|
+
}
|
|
423
|
+
return `${prefix} severity=${severity ?? '?'} ${summary}`;
|
|
424
|
+
}
|
|
402
425
|
default:
|
|
403
426
|
return `${prefix} ${JSON.stringify(obj).slice(0, 120)}`;
|
|
404
427
|
}
|
|
@@ -407,7 +430,7 @@ program
|
|
|
407
430
|
.command('logs')
|
|
408
431
|
.description('Read and display the WorkRail daemon event log. Use --follow to stream new events in real time.')
|
|
409
432
|
.option('--follow', 'Continuously poll the log file for new events (like tail -f)')
|
|
410
|
-
.option('--session <id>', 'Filter events by sessionId
|
|
433
|
+
.option('--session <id>', 'Filter events by sessionId (UUID prefix) or workrailSessionId (sess_xxx prefix)')
|
|
411
434
|
.action(async (options) => {
|
|
412
435
|
const eventsDir = path_1.default.join(os_1.default.homedir(), '.workrail', 'events', 'daemon');
|
|
413
436
|
function todayFilePath() {
|
|
@@ -444,9 +467,11 @@ program
|
|
|
444
467
|
try {
|
|
445
468
|
const obj = JSON.parse(line);
|
|
446
469
|
const sid = typeof obj['sessionId'] === 'string' ? obj['sessionId'] : '';
|
|
447
|
-
|
|
470
|
+
const wrid = typeof obj['workrailSessionId'] === 'string' ? obj['workrailSessionId'] : '';
|
|
471
|
+
const matchesSession = sid.startsWith(options.session) || sid === options.session ||
|
|
472
|
+
wrid.startsWith(options.session) || wrid === options.session;
|
|
473
|
+
if (!matchesSession)
|
|
448
474
|
continue;
|
|
449
|
-
}
|
|
450
475
|
}
|
|
451
476
|
catch {
|
|
452
477
|
continue;
|
|
@@ -468,6 +493,7 @@ program
|
|
|
468
493
|
printLines(result.lines);
|
|
469
494
|
return;
|
|
470
495
|
}
|
|
496
|
+
process.once('SIGINT', () => process.exit(0));
|
|
471
497
|
let currentFilePath = filePath;
|
|
472
498
|
let offset = 0;
|
|
473
499
|
const initial = readNewLines(currentFilePath, 0);
|
|
@@ -495,4 +521,137 @@ program
|
|
|
495
521
|
}
|
|
496
522
|
}
|
|
497
523
|
});
|
|
524
|
+
program
|
|
525
|
+
.command('status <sessionId>')
|
|
526
|
+
.description('Print a health summary for a daemon session. Accepts sessionId (UUID prefix) or workrailSessionId (sess_xxx).')
|
|
527
|
+
.action(async (sessionId) => {
|
|
528
|
+
const eventsDir = path_1.default.join(os_1.default.homedir(), '.workrail', 'events', 'daemon');
|
|
529
|
+
const date = new Date().toISOString().slice(0, 10);
|
|
530
|
+
const filePath = path_1.default.join(eventsDir, `${date}.jsonl`);
|
|
531
|
+
let raw;
|
|
532
|
+
try {
|
|
533
|
+
raw = fs_1.default.readFileSync(filePath, 'utf8');
|
|
534
|
+
}
|
|
535
|
+
catch {
|
|
536
|
+
process.stdout.write(`No events today. Is the daemon running? (Expected: ${filePath})\n`);
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
let workflowId = null;
|
|
540
|
+
let firstTs = null;
|
|
541
|
+
let lastTs = null;
|
|
542
|
+
let llmTurns = 0;
|
|
543
|
+
let stepAdvances = 0;
|
|
544
|
+
let totalToolCalls = 0;
|
|
545
|
+
let failedToolCalls = 0;
|
|
546
|
+
let fatalIssues = 0;
|
|
547
|
+
let errorIssues = 0;
|
|
548
|
+
let warnIssues = 0;
|
|
549
|
+
let sessionOutcome = null;
|
|
550
|
+
let lastToolName = null;
|
|
551
|
+
let lastToolArgs = null;
|
|
552
|
+
let stuckCount = 0;
|
|
553
|
+
let isLive = true;
|
|
554
|
+
for (const line of raw.split('\n')) {
|
|
555
|
+
if (!line.trim())
|
|
556
|
+
continue;
|
|
557
|
+
let obj;
|
|
558
|
+
try {
|
|
559
|
+
obj = JSON.parse(line);
|
|
560
|
+
}
|
|
561
|
+
catch {
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
const sid = typeof obj['sessionId'] === 'string' ? obj['sessionId'] : '';
|
|
565
|
+
const wrid = typeof obj['workrailSessionId'] === 'string' ? obj['workrailSessionId'] : '';
|
|
566
|
+
const matches = sid.startsWith(sessionId) || sid === sessionId ||
|
|
567
|
+
wrid.startsWith(sessionId) || wrid === sessionId;
|
|
568
|
+
if (!matches)
|
|
569
|
+
continue;
|
|
570
|
+
const ts = typeof obj['ts'] === 'number' ? obj['ts'] : null;
|
|
571
|
+
if (ts !== null) {
|
|
572
|
+
if (firstTs === null || ts < firstTs)
|
|
573
|
+
firstTs = ts;
|
|
574
|
+
if (lastTs === null || ts > lastTs)
|
|
575
|
+
lastTs = ts;
|
|
576
|
+
}
|
|
577
|
+
const kind = typeof obj['kind'] === 'string' ? obj['kind'] : '';
|
|
578
|
+
switch (kind) {
|
|
579
|
+
case 'session_started':
|
|
580
|
+
workflowId = typeof obj['workflowId'] === 'string' ? obj['workflowId'] : null;
|
|
581
|
+
break;
|
|
582
|
+
case 'llm_turn_completed':
|
|
583
|
+
llmTurns++;
|
|
584
|
+
break;
|
|
585
|
+
case 'step_advanced':
|
|
586
|
+
stepAdvances++;
|
|
587
|
+
break;
|
|
588
|
+
case 'tool_call_started':
|
|
589
|
+
totalToolCalls++;
|
|
590
|
+
lastToolName = typeof obj['toolName'] === 'string' ? obj['toolName'] : null;
|
|
591
|
+
lastToolArgs = typeof obj['argsSummary'] === 'string' ? String(obj['argsSummary']).slice(0, 60) : null;
|
|
592
|
+
break;
|
|
593
|
+
case 'tool_call_failed':
|
|
594
|
+
failedToolCalls++;
|
|
595
|
+
break;
|
|
596
|
+
case 'issue_reported': {
|
|
597
|
+
const severity = obj['severity'];
|
|
598
|
+
if (severity === 'fatal')
|
|
599
|
+
fatalIssues++;
|
|
600
|
+
else if (severity === 'error')
|
|
601
|
+
errorIssues++;
|
|
602
|
+
else if (severity === 'warn')
|
|
603
|
+
warnIssues++;
|
|
604
|
+
break;
|
|
605
|
+
}
|
|
606
|
+
case 'agent_stuck':
|
|
607
|
+
stuckCount++;
|
|
608
|
+
break;
|
|
609
|
+
case 'session_completed':
|
|
610
|
+
sessionOutcome = typeof obj['outcome'] === 'string' ? obj['outcome'] : null;
|
|
611
|
+
isLive = false;
|
|
612
|
+
break;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
if (firstTs === null) {
|
|
616
|
+
process.stdout.write(`No events found for session: ${sessionId}\n`);
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
const durationMs = (lastTs ?? firstTs) - firstTs;
|
|
620
|
+
const durationSec = Math.floor(durationMs / 1000);
|
|
621
|
+
const durationMin = Math.floor(durationSec / 60);
|
|
622
|
+
const durationRemSec = durationSec % 60;
|
|
623
|
+
const durationStr = durationMin > 0
|
|
624
|
+
? `${durationMin}m ${durationRemSec}s`
|
|
625
|
+
: `${durationSec}s`;
|
|
626
|
+
const avgTurnSec = llmTurns > 0 ? (durationMs / llmTurns / 1000).toFixed(1) : '?';
|
|
627
|
+
const failRate = totalToolCalls > 0 ? ((failedToolCalls / totalToolCalls) * 100).toFixed(1) : '0';
|
|
628
|
+
const sessionStatus = sessionOutcome !== null
|
|
629
|
+
? sessionOutcome.toUpperCase()
|
|
630
|
+
: (isLive ? 'RUNNING' : 'UNKNOWN');
|
|
631
|
+
const issueStr = (fatalIssues + errorIssues + warnIssues) > 0
|
|
632
|
+
? `${fatalIssues + errorIssues + warnIssues} (${fatalIssues} fatal, ${errorIssues} error, ${warnIssues} warn)`
|
|
633
|
+
: '0';
|
|
634
|
+
const lastActivityStr = lastTs !== null
|
|
635
|
+
? `${lastToolName ?? 'unknown'} ${lastToolArgs ? `"${lastToolArgs}"` : ''} ${Math.round((Date.now() - lastTs) / 1000)}s ago`
|
|
636
|
+
: 'unknown';
|
|
637
|
+
process.stdout.write(`\nSession: ${sessionId} [${sessionStatus}]\n`);
|
|
638
|
+
if (workflowId)
|
|
639
|
+
process.stdout.write(`Workflow: ${workflowId}\n`);
|
|
640
|
+
process.stdout.write(`Duration: ${durationStr}\n`);
|
|
641
|
+
process.stdout.write(`LLM turns: ${llmTurns}${llmTurns > 0 ? ` (avg ${avgTurnSec}s each)` : ''}\n`);
|
|
642
|
+
process.stdout.write(`Step advances: ${stepAdvances}\n`);
|
|
643
|
+
process.stdout.write(`Tool calls: ${totalToolCalls} (${failedToolCalls} failed, ${failRate}% failure rate)\n`);
|
|
644
|
+
process.stdout.write(`Issues reported: ${issueStr}\n`);
|
|
645
|
+
process.stdout.write(`Last activity: ${lastActivityStr}\n`);
|
|
646
|
+
if (stuckCount > 0) {
|
|
647
|
+
process.stdout.write(`*** WARNING: ${stuckCount} stuck signal(s) detected\n`);
|
|
648
|
+
}
|
|
649
|
+
if (fatalIssues > 0) {
|
|
650
|
+
process.stdout.write(`*** WARNING: ${fatalIssues} FATAL issue(s) reported\n`);
|
|
651
|
+
}
|
|
652
|
+
if (llmTurns >= 10 && stepAdvances === 0) {
|
|
653
|
+
process.stdout.write(`*** WARNING: ${llmTurns} turns with 0 step advances (possible stuck)\n`);
|
|
654
|
+
}
|
|
655
|
+
process.stdout.write('\n');
|
|
656
|
+
});
|
|
498
657
|
program.parse();
|