@covibes/zeroshot 1.3.0 → 1.5.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/CHANGELOG.md +50 -0
- package/cli/index.js +131 -49
- package/cli/message-formatters-normal.js +77 -38
- package/cluster-templates/base-templates/debug-workflow.json +11 -2
- package/cluster-templates/base-templates/full-workflow.json +20 -7
- package/cluster-templates/base-templates/single-worker.json +8 -1
- package/cluster-templates/base-templates/worker-validator.json +10 -2
- package/docker/zeroshot-cluster/Dockerfile +7 -0
- package/package.json +3 -1
- package/src/agent/agent-config.js +19 -6
- package/src/agent/agent-context-builder.js +9 -0
- package/src/agent/agent-task-executor.js +149 -65
- package/src/config-validator.js +13 -0
- package/src/isolation-manager.js +11 -7
- package/src/orchestrator.js +78 -1
- package/src/status-footer.js +188 -42
- package/src/template-resolver.js +23 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,53 @@
|
|
|
1
|
+
# [1.5.0](https://github.com/covibes/zeroshot/compare/v1.4.0...v1.5.0) (2025-12-28)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **agent:** stop polling after max failures and fix status matching ([7a0fbfe](https://github.com/covibes/zeroshot/commit/7a0fbfe5439f428bdf8e0bcadbd308542221b6f1))
|
|
7
|
+
* **ci:** skip pre-push hook in CI environment ([352b013](https://github.com/covibes/zeroshot/commit/352b013b71fcea7c2d484c8274fe7c42139c65ea))
|
|
8
|
+
* **cli:** prevent terminal garbling with status footer coordination ([2716ce5](https://github.com/covibes/zeroshot/commit/2716ce55eae9a08107788200ab798c3f76815820))
|
|
9
|
+
* **config:** add timeout: 0 default to agent configuration ([6ff66c0](https://github.com/covibes/zeroshot/commit/6ff66c093bf8dfd5048b468fbd250cbfc0d9dbc1))
|
|
10
|
+
* **deps:** regenerate package-lock.json for jscpd dependencies ([c46d84c](https://github.com/covibes/zeroshot/commit/c46d84c3fc1fbb3d00585922613ff36d829d917a))
|
|
11
|
+
* **infra:** improve container cleanup and npm install robustness ([6c04b46](https://github.com/covibes/zeroshot/commit/6c04b46374bd3041a8b5c185ca163009f2fb6635))
|
|
12
|
+
* **orchestrator:** prevent 0-message clusters on SIGINT during init ([33ed8f9](https://github.com/covibes/zeroshot/commit/33ed8f9b90d92da6bf9caf2a7b5e52eadbcecc9f))
|
|
13
|
+
* **template-resolver:** apply param defaults before resolving placeholders ([eafdd62](https://github.com/covibes/zeroshot/commit/eafdd62fce381a7b9a7cb9787cd06e13f421171b))
|
|
14
|
+
* **templates:** add timeout parameter to all base templates ([f853ed3](https://github.com/covibes/zeroshot/commit/f853ed39e0e566afaf31040ce94923a2dcc7bfb9))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* **agents:** add git prohibition + minimal output instructions ([6f6496c](https://github.com/covibes/zeroshot/commit/6f6496c5db29073ebbeb6229ac128a5f62d7591f))
|
|
20
|
+
* mechanical enforcement of 7 antipatterns ([4286091](https://github.com/covibes/zeroshot/commit/428609163f9405a8d4b9e84adaee0edbc6bbb7d1)), closes [#1](https://github.com/covibes/zeroshot/issues/1) [#5](https://github.com/covibes/zeroshot/issues/5) [#2](https://github.com/covibes/zeroshot/issues/2) [#4](https://github.com/covibes/zeroshot/issues/4) [#3](https://github.com/covibes/zeroshot/issues/3) [#7](https://github.com/covibes/zeroshot/issues/7) [covibes/covibes#635](https://github.com/covibes/covibes/issues/635)
|
|
21
|
+
* **templates:** add timeout parameter to worker-validator agents ([ee8b17b](https://github.com/covibes/zeroshot/commit/ee8b17bc76aa29bb692965fddbc5a993749f11f9))
|
|
22
|
+
|
|
23
|
+
# [1.5.0](https://github.com/covibes/zeroshot/compare/v1.4.0...v1.5.0) (2025-12-28)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Bug Fixes
|
|
27
|
+
|
|
28
|
+
* **agent:** stop polling after max failures and fix status matching ([7a0fbfe](https://github.com/covibes/zeroshot/commit/7a0fbfe5439f428bdf8e0bcadbd308542221b6f1))
|
|
29
|
+
* **cli:** prevent terminal garbling with status footer coordination ([2716ce5](https://github.com/covibes/zeroshot/commit/2716ce55eae9a08107788200ab798c3f76815820))
|
|
30
|
+
* **config:** add timeout: 0 default to agent configuration ([6ff66c0](https://github.com/covibes/zeroshot/commit/6ff66c093bf8dfd5048b468fbd250cbfc0d9dbc1))
|
|
31
|
+
* **deps:** regenerate package-lock.json for jscpd dependencies ([c46d84c](https://github.com/covibes/zeroshot/commit/c46d84c3fc1fbb3d00585922613ff36d829d917a))
|
|
32
|
+
* **infra:** improve container cleanup and npm install robustness ([6c04b46](https://github.com/covibes/zeroshot/commit/6c04b46374bd3041a8b5c185ca163009f2fb6635))
|
|
33
|
+
* **orchestrator:** prevent 0-message clusters on SIGINT during init ([33ed8f9](https://github.com/covibes/zeroshot/commit/33ed8f9b90d92da6bf9caf2a7b5e52eadbcecc9f))
|
|
34
|
+
* **template-resolver:** apply param defaults before resolving placeholders ([eafdd62](https://github.com/covibes/zeroshot/commit/eafdd62fce381a7b9a7cb9787cd06e13f421171b))
|
|
35
|
+
* **templates:** add timeout parameter to all base templates ([f853ed3](https://github.com/covibes/zeroshot/commit/f853ed39e0e566afaf31040ce94923a2dcc7bfb9))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
### Features
|
|
39
|
+
|
|
40
|
+
* **agents:** add git prohibition + minimal output instructions ([6f6496c](https://github.com/covibes/zeroshot/commit/6f6496c5db29073ebbeb6229ac128a5f62d7591f))
|
|
41
|
+
* mechanical enforcement of 7 antipatterns ([4286091](https://github.com/covibes/zeroshot/commit/428609163f9405a8d4b9e84adaee0edbc6bbb7d1)), closes [#1](https://github.com/covibes/zeroshot/issues/1) [#5](https://github.com/covibes/zeroshot/issues/5) [#2](https://github.com/covibes/zeroshot/issues/2) [#4](https://github.com/covibes/zeroshot/issues/4) [#3](https://github.com/covibes/zeroshot/issues/3) [#7](https://github.com/covibes/zeroshot/issues/7) [covibes/covibes#635](https://github.com/covibes/covibes/issues/635)
|
|
42
|
+
* **templates:** add timeout parameter to worker-validator agents ([ee8b17b](https://github.com/covibes/zeroshot/commit/ee8b17bc76aa29bb692965fddbc5a993749f11f9))
|
|
43
|
+
|
|
44
|
+
# [1.4.0](https://github.com/covibes/zeroshot/compare/v1.3.0...v1.4.0) (2025-12-28)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
### Features
|
|
48
|
+
|
|
49
|
+
* **status-footer:** atomic writes + token cost display ([7baf0c2](https://github.com/covibes/zeroshot/commit/7baf0c228dd5f3489013f75a1782abe6cbe39661))
|
|
50
|
+
|
|
1
51
|
# [1.3.0](https://github.com/covibes/zeroshot/compare/v1.2.0...v1.3.0) (2025-12-28)
|
|
2
52
|
|
|
3
53
|
|
package/cli/index.js
CHANGED
|
@@ -60,6 +60,39 @@ let activeClusterId = null;
|
|
|
60
60
|
/** @type {import('../src/orchestrator') | null} */
|
|
61
61
|
let orchestratorInstance = null;
|
|
62
62
|
|
|
63
|
+
// Track active status footer for safe output routing
|
|
64
|
+
// When set, all output routes through statusFooter.print() to prevent garbling
|
|
65
|
+
/** @type {import('../src/status-footer').StatusFooter | null} */
|
|
66
|
+
let activeStatusFooter = null;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Safe print - routes through statusFooter when active to prevent garbling
|
|
70
|
+
* @param {...any} args - Arguments to print (like console.log)
|
|
71
|
+
*/
|
|
72
|
+
function safePrint(...args) {
|
|
73
|
+
const text = args.map(arg =>
|
|
74
|
+
typeof arg === 'string' ? arg : String(arg)
|
|
75
|
+
).join(' ');
|
|
76
|
+
|
|
77
|
+
if (activeStatusFooter) {
|
|
78
|
+
activeStatusFooter.print(text + '\n');
|
|
79
|
+
} else {
|
|
80
|
+
console.log(...args);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Safe write - routes through statusFooter when active
|
|
86
|
+
* @param {string} text - Text to write
|
|
87
|
+
*/
|
|
88
|
+
function safeWrite(text) {
|
|
89
|
+
if (activeStatusFooter) {
|
|
90
|
+
activeStatusFooter.print(text);
|
|
91
|
+
} else {
|
|
92
|
+
process.stdout.write(text);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
63
96
|
/**
|
|
64
97
|
* Handle fatal errors: log, cleanup cluster state, exit
|
|
65
98
|
* @param {string} type - 'uncaughtException' or 'unhandledRejection'
|
|
@@ -613,6 +646,9 @@ Input formats:
|
|
|
613
646
|
});
|
|
614
647
|
statusFooter.setCluster(clusterId);
|
|
615
648
|
statusFooter.setClusterState('running');
|
|
649
|
+
statusFooter.setMessageBus(cluster.messageBus);
|
|
650
|
+
// Set module-level reference so safePrint/safeWrite route through footer
|
|
651
|
+
activeStatusFooter = statusFooter;
|
|
616
652
|
|
|
617
653
|
// Subscribe to AGENT_LIFECYCLE to track agent states and PIDs
|
|
618
654
|
const lifecycleUnsubscribe = cluster.messageBus.subscribeTopic('AGENT_LIFECYCLE', (msg) => {
|
|
@@ -697,14 +733,16 @@ Input formats:
|
|
|
697
733
|
if (status.state !== 'running') {
|
|
698
734
|
clearInterval(checkInterval);
|
|
699
735
|
clearInterval(flushInterval);
|
|
700
|
-
// Stop status footer
|
|
701
|
-
statusFooter.stop();
|
|
702
736
|
lifecycleUnsubscribe();
|
|
703
|
-
// Final flush
|
|
737
|
+
// Final flush BEFORE stopping status footer
|
|
738
|
+
// (statusFooter.stop() sends ANSI codes that can clear terminal area)
|
|
704
739
|
for (const sender of sendersWithOutput) {
|
|
705
740
|
const prefix = getColorForSender(sender)(`${sender.padEnd(15)} |`);
|
|
706
741
|
flushLineBuffer(prefix, sender);
|
|
707
742
|
}
|
|
743
|
+
// Stop status footer AFTER output is done
|
|
744
|
+
statusFooter.stop();
|
|
745
|
+
activeStatusFooter = null;
|
|
708
746
|
unsubscribe();
|
|
709
747
|
resolve();
|
|
710
748
|
}
|
|
@@ -713,6 +751,7 @@ Input formats:
|
|
|
713
751
|
clearInterval(checkInterval);
|
|
714
752
|
clearInterval(flushInterval);
|
|
715
753
|
statusFooter.stop();
|
|
754
|
+
activeStatusFooter = null;
|
|
716
755
|
lifecycleUnsubscribe();
|
|
717
756
|
unsubscribe();
|
|
718
757
|
resolve();
|
|
@@ -725,6 +764,7 @@ Input formats:
|
|
|
725
764
|
process.on('SIGINT', async () => {
|
|
726
765
|
// Stop status footer first to restore terminal
|
|
727
766
|
statusFooter.stop();
|
|
767
|
+
activeStatusFooter = null;
|
|
728
768
|
lifecycleUnsubscribe();
|
|
729
769
|
|
|
730
770
|
console.log(chalk.dim('\n\n--- Interrupted ---'));
|
|
@@ -749,6 +789,22 @@ Input formats:
|
|
|
749
789
|
}
|
|
750
790
|
|
|
751
791
|
// Daemon mode: cluster runs in background, stay alive via orchestrator's setInterval
|
|
792
|
+
// Add cleanup handlers for daemon mode to ensure container cleanup on process exit
|
|
793
|
+
// CRITICAL: Without this, containers become orphaned when daemon process dies
|
|
794
|
+
if (process.env.CREW_DAEMON) {
|
|
795
|
+
const cleanup = async (signal) => {
|
|
796
|
+
console.log(`\n[DAEMON] Received ${signal}, cleaning up cluster ${clusterId}...`);
|
|
797
|
+
try {
|
|
798
|
+
await orchestrator.stop(clusterId);
|
|
799
|
+
console.log(`[DAEMON] Cluster ${clusterId} stopped.`);
|
|
800
|
+
} catch (e) {
|
|
801
|
+
console.error(`[DAEMON] Cleanup error: ${e.message}`);
|
|
802
|
+
}
|
|
803
|
+
process.exit(0);
|
|
804
|
+
};
|
|
805
|
+
process.on('SIGTERM', () => cleanup('SIGTERM'));
|
|
806
|
+
process.on('SIGINT', () => cleanup('SIGINT'));
|
|
807
|
+
}
|
|
752
808
|
} catch (error) {
|
|
753
809
|
console.error('Error:', error.message);
|
|
754
810
|
process.exit(1);
|
|
@@ -3569,32 +3625,40 @@ function accumulateText(prefix, sender, text) {
|
|
|
3569
3625
|
buf.textBuffer = buf.textBuffer.slice(newlineIdx + 1);
|
|
3570
3626
|
|
|
3571
3627
|
// Word wrap and print the complete line
|
|
3628
|
+
// CRITICAL: Batch all output into single safeWrite() to prevent interleaving with render()
|
|
3572
3629
|
const wrappedLines = wordWrap(completeLine, contentWidth);
|
|
3630
|
+
let outputBuffer = '';
|
|
3631
|
+
|
|
3573
3632
|
for (let i = 0; i < wrappedLines.length; i++) {
|
|
3574
3633
|
const wrappedLine = wrappedLines[i];
|
|
3575
3634
|
|
|
3576
3635
|
// Print prefix (real or continuation)
|
|
3577
3636
|
if (buf.needsPrefix) {
|
|
3578
|
-
|
|
3637
|
+
outputBuffer += `${prefix} `;
|
|
3579
3638
|
buf.needsPrefix = false;
|
|
3580
3639
|
} else if (i > 0) {
|
|
3581
|
-
|
|
3640
|
+
outputBuffer += `${continuationPrefix}`;
|
|
3582
3641
|
}
|
|
3583
3642
|
|
|
3584
3643
|
if (wrappedLine.trim()) {
|
|
3585
|
-
|
|
3644
|
+
outputBuffer += formatInlineMarkdown(wrappedLine);
|
|
3586
3645
|
}
|
|
3587
3646
|
|
|
3588
3647
|
// Newline after each wrapped segment
|
|
3589
3648
|
if (i < wrappedLines.length - 1) {
|
|
3590
|
-
|
|
3649
|
+
outputBuffer += '\n';
|
|
3591
3650
|
}
|
|
3592
3651
|
}
|
|
3593
3652
|
|
|
3594
3653
|
// Complete the line
|
|
3595
|
-
|
|
3654
|
+
outputBuffer += '\n';
|
|
3596
3655
|
buf.needsPrefix = true;
|
|
3597
3656
|
buf.pendingNewline = false;
|
|
3657
|
+
|
|
3658
|
+
// Single atomic write prevents interleaving
|
|
3659
|
+
if (outputBuffer) {
|
|
3660
|
+
safeWrite(outputBuffer);
|
|
3661
|
+
}
|
|
3598
3662
|
}
|
|
3599
3663
|
|
|
3600
3664
|
// Mark that we have pending text (no newline yet)
|
|
@@ -3619,35 +3683,45 @@ function accumulateThinking(prefix, sender, text) {
|
|
|
3619
3683
|
const newlineIdx = remaining.indexOf('\n');
|
|
3620
3684
|
const rawLine = newlineIdx === -1 ? remaining : remaining.slice(0, newlineIdx);
|
|
3621
3685
|
|
|
3686
|
+
// CRITICAL: Batch all output into single safeWrite() to prevent interleaving with render()
|
|
3622
3687
|
const wrappedLines = wordWrap(rawLine, contentWidth);
|
|
3688
|
+
let outputBuffer = '';
|
|
3623
3689
|
|
|
3624
3690
|
for (let i = 0; i < wrappedLines.length; i++) {
|
|
3625
3691
|
const wrappedLine = wrappedLines[i];
|
|
3626
3692
|
|
|
3627
3693
|
if (buf.thinkingNeedsPrefix) {
|
|
3628
|
-
|
|
3694
|
+
outputBuffer += `${prefix} ${chalk.dim.italic('💭 ')}`;
|
|
3629
3695
|
buf.thinkingNeedsPrefix = false;
|
|
3630
3696
|
} else if (i > 0) {
|
|
3631
|
-
|
|
3697
|
+
outputBuffer += `${continuationPrefix}`;
|
|
3632
3698
|
}
|
|
3633
3699
|
|
|
3634
3700
|
if (wrappedLine.trim()) {
|
|
3635
|
-
|
|
3701
|
+
outputBuffer += chalk.dim.italic(wrappedLine);
|
|
3636
3702
|
}
|
|
3637
3703
|
|
|
3638
3704
|
if (i < wrappedLines.length - 1) {
|
|
3639
|
-
|
|
3705
|
+
outputBuffer += '\n';
|
|
3640
3706
|
}
|
|
3641
3707
|
}
|
|
3642
3708
|
|
|
3643
3709
|
if (newlineIdx === -1) {
|
|
3644
3710
|
buf.thinkingPendingNewline = true;
|
|
3711
|
+
// Single atomic write
|
|
3712
|
+
if (outputBuffer) {
|
|
3713
|
+
safeWrite(outputBuffer);
|
|
3714
|
+
}
|
|
3645
3715
|
break;
|
|
3646
3716
|
} else {
|
|
3647
|
-
|
|
3717
|
+
outputBuffer += '\n';
|
|
3648
3718
|
buf.thinkingNeedsPrefix = true;
|
|
3649
3719
|
buf.thinkingPendingNewline = false;
|
|
3650
3720
|
remaining = remaining.slice(newlineIdx + 1);
|
|
3721
|
+
// Single atomic write
|
|
3722
|
+
if (outputBuffer) {
|
|
3723
|
+
safeWrite(outputBuffer);
|
|
3724
|
+
}
|
|
3651
3725
|
}
|
|
3652
3726
|
}
|
|
3653
3727
|
}
|
|
@@ -3657,7 +3731,10 @@ function flushLineBuffer(prefix, sender) {
|
|
|
3657
3731
|
const buf = lineBuffers.get(sender);
|
|
3658
3732
|
if (!buf) return;
|
|
3659
3733
|
|
|
3660
|
-
// CRITICAL:
|
|
3734
|
+
// CRITICAL: Batch all output into single safeWrite() to prevent interleaving with render()
|
|
3735
|
+
let outputBuffer = '';
|
|
3736
|
+
|
|
3737
|
+
// Flush any remaining text in textBuffer (text without trailing newline)
|
|
3661
3738
|
if (buf.textBuffer && buf.textBuffer.length > 0) {
|
|
3662
3739
|
// Calculate widths for word wrapping (same as accumulateText)
|
|
3663
3740
|
const prefixLen = chalk.reset(prefix).replace(/\\x1b\[[0-9;]*m/g, '').length + 1;
|
|
@@ -3670,18 +3747,18 @@ function flushLineBuffer(prefix, sender) {
|
|
|
3670
3747
|
const wrappedLine = wrappedLines[i];
|
|
3671
3748
|
|
|
3672
3749
|
if (buf.needsPrefix) {
|
|
3673
|
-
|
|
3750
|
+
outputBuffer += `${prefix} `;
|
|
3674
3751
|
buf.needsPrefix = false;
|
|
3675
3752
|
} else if (i > 0) {
|
|
3676
|
-
|
|
3753
|
+
outputBuffer += `${continuationPrefix}`;
|
|
3677
3754
|
}
|
|
3678
3755
|
|
|
3679
3756
|
if (wrappedLine.trim()) {
|
|
3680
|
-
|
|
3757
|
+
outputBuffer += formatInlineMarkdown(wrappedLine);
|
|
3681
3758
|
}
|
|
3682
3759
|
|
|
3683
3760
|
if (i < wrappedLines.length - 1) {
|
|
3684
|
-
|
|
3761
|
+
outputBuffer += '\n';
|
|
3685
3762
|
}
|
|
3686
3763
|
}
|
|
3687
3764
|
|
|
@@ -3691,15 +3768,20 @@ function flushLineBuffer(prefix, sender) {
|
|
|
3691
3768
|
}
|
|
3692
3769
|
|
|
3693
3770
|
if (buf.pendingNewline) {
|
|
3694
|
-
|
|
3771
|
+
outputBuffer += '\n';
|
|
3695
3772
|
buf.needsPrefix = true;
|
|
3696
3773
|
buf.pendingNewline = false;
|
|
3697
3774
|
}
|
|
3698
3775
|
if (buf.thinkingPendingNewline) {
|
|
3699
|
-
|
|
3776
|
+
outputBuffer += '\n';
|
|
3700
3777
|
buf.thinkingNeedsPrefix = true;
|
|
3701
3778
|
buf.thinkingPendingNewline = false;
|
|
3702
3779
|
}
|
|
3780
|
+
|
|
3781
|
+
// Single atomic write prevents interleaving
|
|
3782
|
+
if (outputBuffer) {
|
|
3783
|
+
safeWrite(outputBuffer);
|
|
3784
|
+
}
|
|
3703
3785
|
}
|
|
3704
3786
|
|
|
3705
3787
|
// Lines to filter out (noise, metadata, errors)
|
|
@@ -3782,17 +3864,17 @@ function printMessage(msg, showClusterId = false, watchMode = false, isActive =
|
|
|
3782
3864
|
}
|
|
3783
3865
|
|
|
3784
3866
|
if (msg.topic === 'PR_CREATED') {
|
|
3785
|
-
formatPrCreated(msg, prefix, timestamp);
|
|
3867
|
+
formatPrCreated(msg, prefix, timestamp, safePrint);
|
|
3786
3868
|
return;
|
|
3787
3869
|
}
|
|
3788
3870
|
|
|
3789
3871
|
if (msg.topic === 'CLUSTER_COMPLETE') {
|
|
3790
|
-
formatClusterComplete(msg, prefix, timestamp);
|
|
3872
|
+
formatClusterComplete(msg, prefix, timestamp, safePrint);
|
|
3791
3873
|
return;
|
|
3792
3874
|
}
|
|
3793
3875
|
|
|
3794
3876
|
if (msg.topic === 'CLUSTER_FAILED') {
|
|
3795
|
-
formatClusterFailed(msg, prefix, timestamp);
|
|
3877
|
+
formatClusterFailed(msg, prefix, timestamp, safePrint);
|
|
3796
3878
|
return;
|
|
3797
3879
|
}
|
|
3798
3880
|
|
|
@@ -3818,7 +3900,7 @@ function printMessage(msg, showClusterId = false, watchMode = false, isActive =
|
|
|
3818
3900
|
if (event.text) {
|
|
3819
3901
|
accumulateThinking(prefix, msg.sender, event.text);
|
|
3820
3902
|
} else if (event.type === 'thinking_start') {
|
|
3821
|
-
|
|
3903
|
+
safePrint(`${prefix} ${chalk.dim.italic('💭 thinking...')}`);
|
|
3822
3904
|
}
|
|
3823
3905
|
break;
|
|
3824
3906
|
|
|
@@ -3832,7 +3914,7 @@ function printMessage(msg, showClusterId = false, watchMode = false, isActive =
|
|
|
3832
3914
|
flushLineBuffer(prefix, msg.sender);
|
|
3833
3915
|
const icon = getToolIcon(event.toolName);
|
|
3834
3916
|
const toolDesc = formatToolCall(event.toolName, event.input);
|
|
3835
|
-
|
|
3917
|
+
safePrint(`${prefix} ${icon} ${chalk.cyan(event.toolName)} ${chalk.dim(toolDesc)}`);
|
|
3836
3918
|
// Store tool call info for matching with result
|
|
3837
3919
|
currentToolCall.set(msg.sender, {
|
|
3838
3920
|
toolName: event.toolName,
|
|
@@ -3854,7 +3936,7 @@ function printMessage(msg, showClusterId = false, watchMode = false, isActive =
|
|
|
3854
3936
|
toolCall?.toolName,
|
|
3855
3937
|
toolCall?.input
|
|
3856
3938
|
);
|
|
3857
|
-
|
|
3939
|
+
safePrint(`${prefix} ${status} ${resultDesc}`);
|
|
3858
3940
|
// Clear stored tool call after result
|
|
3859
3941
|
currentToolCall.delete(msg.sender);
|
|
3860
3942
|
break;
|
|
@@ -3864,7 +3946,7 @@ function printMessage(msg, showClusterId = false, watchMode = false, isActive =
|
|
|
3864
3946
|
flushLineBuffer(prefix, msg.sender);
|
|
3865
3947
|
// Final result - only show errors (success text already streamed)
|
|
3866
3948
|
if (!event.success) {
|
|
3867
|
-
|
|
3949
|
+
safePrint(`${prefix} ${chalk.bold.red('✗ Error:')} ${event.error || 'Task failed'}`);
|
|
3868
3950
|
}
|
|
3869
3951
|
break;
|
|
3870
3952
|
|
|
@@ -3905,7 +3987,7 @@ function printMessage(msg, showClusterId = false, watchMode = false, isActive =
|
|
|
3905
3987
|
// Skip duplicate content
|
|
3906
3988
|
if (isDuplicate(trimmed)) continue;
|
|
3907
3989
|
|
|
3908
|
-
|
|
3990
|
+
safePrint(`${prefix} ${line}`);
|
|
3909
3991
|
}
|
|
3910
3992
|
}
|
|
3911
3993
|
return;
|
|
@@ -3913,22 +3995,22 @@ function printMessage(msg, showClusterId = false, watchMode = false, isActive =
|
|
|
3913
3995
|
|
|
3914
3996
|
// AGENT_ERROR: Show errors with visual prominence
|
|
3915
3997
|
if (msg.topic === 'AGENT_ERROR') {
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3998
|
+
safePrint(''); // Blank line before error
|
|
3999
|
+
safePrint(chalk.bold.red(`${'─'.repeat(60)}`));
|
|
4000
|
+
safePrint(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.red('🔴 AGENT ERROR')}`);
|
|
3919
4001
|
if (msg.content?.text) {
|
|
3920
|
-
|
|
4002
|
+
safePrint(`${prefix} ${chalk.red(msg.content.text)}`);
|
|
3921
4003
|
}
|
|
3922
4004
|
if (msg.content?.data?.stack) {
|
|
3923
4005
|
// Show first 5 lines of stack trace
|
|
3924
4006
|
const stackLines = msg.content.data.stack.split('\n').slice(0, 5);
|
|
3925
4007
|
for (const line of stackLines) {
|
|
3926
4008
|
if (line.trim()) {
|
|
3927
|
-
|
|
4009
|
+
safePrint(`${prefix} ${chalk.dim(line)}`);
|
|
3928
4010
|
}
|
|
3929
4011
|
}
|
|
3930
4012
|
}
|
|
3931
|
-
|
|
4013
|
+
safePrint(chalk.bold.red(`${'─'.repeat(60)}`));
|
|
3932
4014
|
return;
|
|
3933
4015
|
}
|
|
3934
4016
|
|
|
@@ -3940,29 +4022,29 @@ function printMessage(msg, showClusterId = false, watchMode = false, isActive =
|
|
|
3940
4022
|
}
|
|
3941
4023
|
shownNewTaskForCluster.add(msg.cluster_id);
|
|
3942
4024
|
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
4025
|
+
safePrint(''); // Blank line before new task
|
|
4026
|
+
safePrint(chalk.bold.blue(`${'─'.repeat(60)}`));
|
|
4027
|
+
safePrint(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.blue('📋 NEW TASK')}`);
|
|
3946
4028
|
if (msg.content?.text) {
|
|
3947
4029
|
// Show task description (first 3 lines max)
|
|
3948
4030
|
const lines = msg.content.text.split('\n').slice(0, 3);
|
|
3949
4031
|
for (const line of lines) {
|
|
3950
4032
|
if (line.trim() && line.trim() !== '# Manual Input') {
|
|
3951
|
-
|
|
4033
|
+
safePrint(`${prefix} ${chalk.white(line)}`);
|
|
3952
4034
|
}
|
|
3953
4035
|
}
|
|
3954
4036
|
}
|
|
3955
|
-
|
|
4037
|
+
safePrint(chalk.bold.blue(`${'─'.repeat(60)}`));
|
|
3956
4038
|
return;
|
|
3957
4039
|
}
|
|
3958
4040
|
|
|
3959
4041
|
// IMPLEMENTATION_READY: milestone marker
|
|
3960
4042
|
if (msg.topic === 'IMPLEMENTATION_READY') {
|
|
3961
|
-
|
|
4043
|
+
safePrint(
|
|
3962
4044
|
`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.yellow('✅ IMPLEMENTATION READY')}`
|
|
3963
4045
|
);
|
|
3964
4046
|
if (msg.content?.data?.commit) {
|
|
3965
|
-
|
|
4047
|
+
safePrint(
|
|
3966
4048
|
`${prefix} ${chalk.gray('Commit:')} ${chalk.cyan(msg.content.data.commit.substring(0, 8))}`
|
|
3967
4049
|
);
|
|
3968
4050
|
}
|
|
@@ -3975,33 +4057,33 @@ function printMessage(msg, showClusterId = false, watchMode = false, isActive =
|
|
|
3975
4057
|
const approved = data.approved === true || data.approved === 'true';
|
|
3976
4058
|
const status = approved ? chalk.bold.green('✓ APPROVED') : chalk.bold.red('✗ REJECTED');
|
|
3977
4059
|
|
|
3978
|
-
|
|
4060
|
+
safePrint(`${prefix} ${chalk.gray(timestamp)} ${status}`);
|
|
3979
4061
|
|
|
3980
4062
|
// Show summary if present and not a template variable
|
|
3981
4063
|
if (msg.content?.text && !msg.content.text.includes('{{')) {
|
|
3982
|
-
|
|
4064
|
+
safePrint(`${prefix} ${msg.content.text.substring(0, 100)}`);
|
|
3983
4065
|
}
|
|
3984
4066
|
|
|
3985
4067
|
// Show full JSON data structure
|
|
3986
|
-
|
|
4068
|
+
safePrint(
|
|
3987
4069
|
`${prefix} ${chalk.dim(JSON.stringify(data, null, 2).split('\n').join(`\n${prefix} `))}`
|
|
3988
4070
|
);
|
|
3989
4071
|
|
|
3990
4072
|
// Show errors/issues if any
|
|
3991
4073
|
if (data.errors && Array.isArray(data.errors) && data.errors.length > 0) {
|
|
3992
|
-
|
|
4074
|
+
safePrint(`${prefix} ${chalk.red('Errors:')}`);
|
|
3993
4075
|
data.errors.forEach((err) => {
|
|
3994
4076
|
if (err && typeof err === 'string') {
|
|
3995
|
-
|
|
4077
|
+
safePrint(`${prefix} - ${err}`);
|
|
3996
4078
|
}
|
|
3997
4079
|
});
|
|
3998
4080
|
}
|
|
3999
4081
|
|
|
4000
4082
|
if (data.issues && Array.isArray(data.issues) && data.issues.length > 0) {
|
|
4001
|
-
|
|
4083
|
+
safePrint(`${prefix} ${chalk.yellow('Issues:')}`);
|
|
4002
4084
|
data.issues.forEach((issue) => {
|
|
4003
4085
|
if (issue && typeof issue === 'string') {
|
|
4004
|
-
|
|
4086
|
+
safePrint(`${prefix} - ${issue}`);
|
|
4005
4087
|
}
|
|
4006
4088
|
});
|
|
4007
4089
|
}
|
|
@@ -4009,7 +4091,7 @@ function printMessage(msg, showClusterId = false, watchMode = false, isActive =
|
|
|
4009
4091
|
}
|
|
4010
4092
|
|
|
4011
4093
|
// Fallback: generic message display for unknown topics
|
|
4012
|
-
formatGenericMessage(msg, prefix, timestamp);
|
|
4094
|
+
formatGenericMessage(msg, prefix, timestamp, safePrint);
|
|
4013
4095
|
}
|
|
4014
4096
|
|
|
4015
4097
|
// Default command handling: if first arg doesn't match a known command, treat it as 'run'
|