@covibes/zeroshot 1.4.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 +43 -0
- package/cli/index.js +130 -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 +59 -6
- package/src/template-resolver.js +23 -1
package/src/status-footer.js
CHANGED
|
@@ -96,6 +96,11 @@ class StatusFooter {
|
|
|
96
96
|
this.minRows = 8; // Minimum rows for footer display (graceful degradation)
|
|
97
97
|
this.hidden = false; // True when terminal too small for footer
|
|
98
98
|
|
|
99
|
+
// Output queue - serializes all stdout to prevent cursor corruption
|
|
100
|
+
// When scroll region is active, console.log() can corrupt cursor position
|
|
101
|
+
// All output must go through print() to coordinate with render cycles
|
|
102
|
+
this.printQueue = [];
|
|
103
|
+
|
|
99
104
|
// Debounced resize handler (100ms) - prevents rapid-fire redraws
|
|
100
105
|
this._debouncedResize = debounce(() => this._handleResize(), 100);
|
|
101
106
|
}
|
|
@@ -108,6 +113,38 @@ class StatusFooter {
|
|
|
108
113
|
return process.stdout.isTTY === true;
|
|
109
114
|
}
|
|
110
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Print text to stdout, coordinating with the render cycle.
|
|
118
|
+
* When a render is in progress, queues output to prevent cursor corruption.
|
|
119
|
+
* When no render is active, writes immediately.
|
|
120
|
+
*
|
|
121
|
+
* MUST be used instead of console.log() when status footer is active.
|
|
122
|
+
* @param {string} text - Text to print (newline will be added)
|
|
123
|
+
*/
|
|
124
|
+
print(text) {
|
|
125
|
+
if (this.isRendering) {
|
|
126
|
+
// Queue for later - render() will flush after restoring cursor
|
|
127
|
+
this.printQueue.push(text);
|
|
128
|
+
} else {
|
|
129
|
+
// Write immediately - no render in progress
|
|
130
|
+
process.stdout.write(text + '\n');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Flush queued output to stdout.
|
|
136
|
+
* Called after render() restores cursor to ensure proper positioning.
|
|
137
|
+
* @private
|
|
138
|
+
*/
|
|
139
|
+
_flushPrintQueue() {
|
|
140
|
+
if (this.printQueue.length === 0) return;
|
|
141
|
+
|
|
142
|
+
// Write all queued output
|
|
143
|
+
const output = this.printQueue.map(text => text + '\n').join('');
|
|
144
|
+
this.printQueue = [];
|
|
145
|
+
process.stdout.write(output);
|
|
146
|
+
}
|
|
147
|
+
|
|
111
148
|
/**
|
|
112
149
|
* Get terminal dimensions
|
|
113
150
|
* @returns {{ rows: number, cols: number }}
|
|
@@ -495,6 +532,19 @@ class StatusFooter {
|
|
|
495
532
|
} finally {
|
|
496
533
|
this.isRendering = false;
|
|
497
534
|
|
|
535
|
+
// CRITICAL: Position cursor at bottom of scroll region before flushing
|
|
536
|
+
// Without this, output goes below footer if cursor was restored outside scroll region
|
|
537
|
+
// (RESTORE_CURSOR at line 527 may restore to row outside the scrollable area)
|
|
538
|
+
if (this.scrollRegionSet) {
|
|
539
|
+
const { rows } = this.getTerminalSize();
|
|
540
|
+
const scrollEnd = rows - this.footerHeight;
|
|
541
|
+
process.stdout.write(this._moveToStr(scrollEnd, 1));
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Flush any output that was queued during render
|
|
545
|
+
// Must happen BEFORE pending resize to preserve output order
|
|
546
|
+
this._flushPrintQueue();
|
|
547
|
+
|
|
498
548
|
// Process pending resize if one was queued during render
|
|
499
549
|
if (this.pendingResize) {
|
|
500
550
|
this.pendingResize = false;
|
|
@@ -728,13 +778,15 @@ class StatusFooter {
|
|
|
728
778
|
// Prevents interleaving with agent output during cleanup
|
|
729
779
|
let buffer = '';
|
|
730
780
|
|
|
731
|
-
//
|
|
781
|
+
// CRITICAL: Clear footer area BEFORE resetting scroll region
|
|
782
|
+
// While scroll region is active, footer area contains only status bar content
|
|
783
|
+
// After reset, those lines may contain scrolled output (which we DON'T want to clear)
|
|
784
|
+
buffer += this._clearFooterAreaStr();
|
|
785
|
+
|
|
786
|
+
// Now reset scroll region (full terminal is scrollable again)
|
|
732
787
|
buffer += this._resetScrollRegionStr();
|
|
733
788
|
this.scrollRegionSet = false;
|
|
734
789
|
|
|
735
|
-
// Clear all footer lines
|
|
736
|
-
buffer += this._clearFooterAreaStr();
|
|
737
|
-
|
|
738
790
|
// Move cursor to safe position and show cursor
|
|
739
791
|
const { rows } = this.getTerminalSize();
|
|
740
792
|
const startRow = rows - this.footerHeight + 1;
|
|
@@ -753,9 +805,10 @@ class StatusFooter {
|
|
|
753
805
|
if (!this.isTTY()) return;
|
|
754
806
|
|
|
755
807
|
// Single atomic write for hide operation
|
|
756
|
-
|
|
808
|
+
// CRITICAL: Clear footer BEFORE resetting scroll region (same reason as stop())
|
|
809
|
+
let buffer = this._clearFooterAreaStr();
|
|
810
|
+
buffer += this._resetScrollRegionStr();
|
|
757
811
|
this.scrollRegionSet = false;
|
|
758
|
-
buffer += this._clearFooterAreaStr();
|
|
759
812
|
process.stdout.write(buffer);
|
|
760
813
|
}
|
|
761
814
|
|
package/src/template-resolver.js
CHANGED
|
@@ -43,8 +43,11 @@ class TemplateResolver {
|
|
|
43
43
|
// Validate required params
|
|
44
44
|
this._validateParams(template, params);
|
|
45
45
|
|
|
46
|
+
// Apply defaults for missing params (e.g., timeout: 0)
|
|
47
|
+
const paramsWithDefaults = this._applyDefaults(template, params);
|
|
48
|
+
|
|
46
49
|
// Deep clone and resolve
|
|
47
|
-
const resolved = this._resolveObject(JSON.parse(JSON.stringify(template)),
|
|
50
|
+
const resolved = this._resolveObject(JSON.parse(JSON.stringify(template)), paramsWithDefaults);
|
|
48
51
|
|
|
49
52
|
// Filter out conditional agents that don't meet their condition
|
|
50
53
|
if (resolved.agents) {
|
|
@@ -86,6 +89,25 @@ class TemplateResolver {
|
|
|
86
89
|
}
|
|
87
90
|
}
|
|
88
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Apply template defaults for any missing params
|
|
94
|
+
* @private
|
|
95
|
+
* @param {any} template
|
|
96
|
+
* @param {any} params
|
|
97
|
+
* @returns {any} params with defaults applied
|
|
98
|
+
*/
|
|
99
|
+
_applyDefaults(template, params) {
|
|
100
|
+
if (!template.params) return params;
|
|
101
|
+
|
|
102
|
+
const result = { ...params };
|
|
103
|
+
for (const [name, schema] of Object.entries(template.params)) {
|
|
104
|
+
if (result[name] === undefined && schema.default !== undefined) {
|
|
105
|
+
result[name] = schema.default;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
|
|
89
111
|
/**
|
|
90
112
|
* Recursively resolve placeholders in an object
|
|
91
113
|
* @private
|