@tiflis-io/tiflis-code-workstation 0.3.12 → 0.3.13
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/main.js +116 -26
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -127,7 +127,11 @@ var EnvSchema = z.object({
|
|
|
127
127
|
// Terminal Configuration
|
|
128
128
|
// ─────────────────────────────────────────────────────────────
|
|
129
129
|
/** Terminal output buffer size (number of messages, in-memory only, does not survive restarts) */
|
|
130
|
-
TERMINAL_OUTPUT_BUFFER_SIZE: z.coerce.number().default(
|
|
130
|
+
TERMINAL_OUTPUT_BUFFER_SIZE: z.coerce.number().default(1e4),
|
|
131
|
+
/** Terminal output batch interval in milliseconds (how long to wait before flushing) */
|
|
132
|
+
TERMINAL_BATCH_INTERVAL_MS: z.coerce.number().default(64),
|
|
133
|
+
/** Terminal output batch max size in bytes (flush immediately when exceeded) */
|
|
134
|
+
TERMINAL_BATCH_MAX_SIZE: z.coerce.number().default(4096),
|
|
131
135
|
// Legacy (fallback for STT/TTS if specific keys not set)
|
|
132
136
|
OPENAI_API_KEY: z.string().optional(),
|
|
133
137
|
// ─────────────────────────────────────────────────────────────
|
|
@@ -283,7 +287,7 @@ var SESSION_CONFIG = {
|
|
|
283
287
|
/** Data retention period for terminated sessions (30 days in ms) */
|
|
284
288
|
DATA_RETENTION_MS: 30 * 24 * 60 * 60 * 1e3,
|
|
285
289
|
/** Default terminal output buffer size (number of messages) */
|
|
286
|
-
DEFAULT_TERMINAL_OUTPUT_BUFFER_SIZE:
|
|
290
|
+
DEFAULT_TERMINAL_OUTPUT_BUFFER_SIZE: 1e4
|
|
287
291
|
};
|
|
288
292
|
var AGENT_COMMANDS = {
|
|
289
293
|
cursor: {
|
|
@@ -2588,15 +2592,12 @@ var TerminalSession = class extends Session {
|
|
|
2588
2592
|
return this._masterDeviceId;
|
|
2589
2593
|
}
|
|
2590
2594
|
/**
|
|
2591
|
-
* Sets the master device ID.
|
|
2592
|
-
* @returns true
|
|
2595
|
+
* Sets the master device ID. Always overrides the current master (new subscriber wins).
|
|
2596
|
+
* @returns true (new subscriber always becomes master)
|
|
2593
2597
|
*/
|
|
2594
2598
|
setMaster(deviceId) {
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
return true;
|
|
2598
|
-
}
|
|
2599
|
-
return this._masterDeviceId === deviceId;
|
|
2599
|
+
this._masterDeviceId = deviceId;
|
|
2600
|
+
return true;
|
|
2600
2601
|
}
|
|
2601
2602
|
/**
|
|
2602
2603
|
* Checks if the given device is the master for this session.
|
|
@@ -2917,6 +2918,75 @@ var PtyManager = class {
|
|
|
2917
2918
|
}
|
|
2918
2919
|
};
|
|
2919
2920
|
|
|
2921
|
+
// src/infrastructure/terminal/terminal-output-batcher.ts
|
|
2922
|
+
var TerminalOutputBatcher = class {
|
|
2923
|
+
buffer = "";
|
|
2924
|
+
timeout = null;
|
|
2925
|
+
lastActivityTime = Date.now();
|
|
2926
|
+
outputRate = 0;
|
|
2927
|
+
// Bytes/second estimate (exponential moving average)
|
|
2928
|
+
batchIntervalMs;
|
|
2929
|
+
maxBatchSize;
|
|
2930
|
+
onFlush;
|
|
2931
|
+
constructor(config2) {
|
|
2932
|
+
this.batchIntervalMs = config2.batchIntervalMs;
|
|
2933
|
+
this.maxBatchSize = config2.maxBatchSize;
|
|
2934
|
+
this.onFlush = config2.onFlush;
|
|
2935
|
+
}
|
|
2936
|
+
/**
|
|
2937
|
+
* Appends data to the batch buffer.
|
|
2938
|
+
* Triggers flush based on size threshold or adaptive timeout.
|
|
2939
|
+
*/
|
|
2940
|
+
append(chunk) {
|
|
2941
|
+
this.buffer += chunk;
|
|
2942
|
+
const now = Date.now();
|
|
2943
|
+
const elapsed = Math.max(now - this.lastActivityTime, 1);
|
|
2944
|
+
const instantRate = chunk.length / elapsed * 1e3;
|
|
2945
|
+
this.outputRate = this.outputRate * 0.7 + instantRate * 0.3;
|
|
2946
|
+
this.lastActivityTime = now;
|
|
2947
|
+
if (this.buffer.length >= this.maxBatchSize) {
|
|
2948
|
+
this.flush();
|
|
2949
|
+
return;
|
|
2950
|
+
}
|
|
2951
|
+
if (this.timeout === null) {
|
|
2952
|
+
const adaptiveInterval = this.outputRate > 1e3 ? this.batchIntervalMs : Math.min(8, this.batchIntervalMs);
|
|
2953
|
+
this.timeout = setTimeout(() => this.flush(), adaptiveInterval);
|
|
2954
|
+
}
|
|
2955
|
+
}
|
|
2956
|
+
/**
|
|
2957
|
+
* Immediately flushes the buffer, invoking the onFlush callback.
|
|
2958
|
+
*/
|
|
2959
|
+
flush() {
|
|
2960
|
+
if (this.timeout !== null) {
|
|
2961
|
+
clearTimeout(this.timeout);
|
|
2962
|
+
this.timeout = null;
|
|
2963
|
+
}
|
|
2964
|
+
if (this.buffer.length > 0) {
|
|
2965
|
+
const data = this.buffer;
|
|
2966
|
+
this.buffer = "";
|
|
2967
|
+
this.onFlush(data);
|
|
2968
|
+
}
|
|
2969
|
+
}
|
|
2970
|
+
/**
|
|
2971
|
+
* Disposes the batcher, flushing any pending data.
|
|
2972
|
+
*/
|
|
2973
|
+
dispose() {
|
|
2974
|
+
this.flush();
|
|
2975
|
+
}
|
|
2976
|
+
/**
|
|
2977
|
+
* Returns current buffer size (for debugging/monitoring).
|
|
2978
|
+
*/
|
|
2979
|
+
get pendingSize() {
|
|
2980
|
+
return this.buffer.length;
|
|
2981
|
+
}
|
|
2982
|
+
/**
|
|
2983
|
+
* Returns estimated output rate in bytes/second.
|
|
2984
|
+
*/
|
|
2985
|
+
get currentOutputRate() {
|
|
2986
|
+
return this.outputRate;
|
|
2987
|
+
}
|
|
2988
|
+
};
|
|
2989
|
+
|
|
2920
2990
|
// src/infrastructure/agents/agent-session-manager.ts
|
|
2921
2991
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
2922
2992
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
@@ -9461,7 +9531,7 @@ async function bootstrap() {
|
|
|
9461
9531
|
let currentStreamingBlocks;
|
|
9462
9532
|
if (supervisorIsExecuting) {
|
|
9463
9533
|
const blocks = supervisorMessageAccumulator.get();
|
|
9464
|
-
if (blocks
|
|
9534
|
+
if (blocks.length > 0) {
|
|
9465
9535
|
currentStreamingBlocks = blocks;
|
|
9466
9536
|
}
|
|
9467
9537
|
}
|
|
@@ -10540,7 +10610,7 @@ async function bootstrap() {
|
|
|
10540
10610
|
let streamingMessageId;
|
|
10541
10611
|
if (isExecuting && !beforeSequence) {
|
|
10542
10612
|
const blocks = supervisorMessageAccumulator.get();
|
|
10543
|
-
if (blocks
|
|
10613
|
+
if (blocks.length > 0) {
|
|
10544
10614
|
currentStreamingBlocks = blocks;
|
|
10545
10615
|
streamingMessageId = supervisorMessageAccumulator.getStreamingMessageId() ?? void 0;
|
|
10546
10616
|
}
|
|
@@ -11153,23 +11223,35 @@ async function bootstrap() {
|
|
|
11153
11223
|
}
|
|
11154
11224
|
};
|
|
11155
11225
|
broadcaster.broadcastToAll(JSON.stringify(broadcastMessage));
|
|
11226
|
+
const batcher = new TerminalOutputBatcher({
|
|
11227
|
+
batchIntervalMs: env.TERMINAL_BATCH_INTERVAL_MS,
|
|
11228
|
+
maxBatchSize: env.TERMINAL_BATCH_MAX_SIZE,
|
|
11229
|
+
onFlush: (batchedData) => {
|
|
11230
|
+
const outputMessage = session.addOutputToBuffer(batchedData);
|
|
11231
|
+
const outputEvent = {
|
|
11232
|
+
type: "session.output",
|
|
11233
|
+
session_id: sessionId.value,
|
|
11234
|
+
payload: {
|
|
11235
|
+
content_type: "terminal",
|
|
11236
|
+
content: batchedData,
|
|
11237
|
+
timestamp: outputMessage.timestamp,
|
|
11238
|
+
sequence: outputMessage.sequence
|
|
11239
|
+
}
|
|
11240
|
+
};
|
|
11241
|
+
broadcaster.broadcastToSubscribers(
|
|
11242
|
+
sessionId.value,
|
|
11243
|
+
JSON.stringify(outputEvent)
|
|
11244
|
+
);
|
|
11245
|
+
}
|
|
11246
|
+
});
|
|
11156
11247
|
session.onOutput((data) => {
|
|
11157
|
-
|
|
11158
|
-
const outputEvent = {
|
|
11159
|
-
type: "session.output",
|
|
11160
|
-
session_id: sessionId.value,
|
|
11161
|
-
payload: {
|
|
11162
|
-
content_type: "terminal",
|
|
11163
|
-
content: data,
|
|
11164
|
-
timestamp: outputMessage.timestamp,
|
|
11165
|
-
sequence: outputMessage.sequence
|
|
11166
|
-
}
|
|
11167
|
-
};
|
|
11168
|
-
broadcaster.broadcastToSubscribers(
|
|
11169
|
-
sessionId.value,
|
|
11170
|
-
JSON.stringify(outputEvent)
|
|
11171
|
-
);
|
|
11248
|
+
batcher.append(data);
|
|
11172
11249
|
});
|
|
11250
|
+
const originalTerminate = session.terminate.bind(session);
|
|
11251
|
+
session.terminate = async () => {
|
|
11252
|
+
batcher.dispose();
|
|
11253
|
+
return originalTerminate();
|
|
11254
|
+
};
|
|
11173
11255
|
});
|
|
11174
11256
|
if (env.MOCK_MODE) {
|
|
11175
11257
|
const terminalSession = await sessionManager.createSession({
|
|
@@ -11401,6 +11483,14 @@ bootstrap().catch((error) => {
|
|
|
11401
11483
|
* @copyright 2025 Roman Barinov <rbarinov@gmail.com>
|
|
11402
11484
|
* @license FSL-1.1-NC
|
|
11403
11485
|
*/
|
|
11486
|
+
/**
|
|
11487
|
+
* @file terminal-output-batcher.ts
|
|
11488
|
+
* @copyright 2025 Roman Barinov <rbarinov@gmail.com>
|
|
11489
|
+
* @license FSL-1.1-NC
|
|
11490
|
+
*
|
|
11491
|
+
* Batches terminal output chunks to reduce message frequency and improve performance.
|
|
11492
|
+
* Uses adaptive batching based on output rate for optimal responsiveness.
|
|
11493
|
+
*/
|
|
11404
11494
|
/**
|
|
11405
11495
|
* @file headless-agent-executor.ts
|
|
11406
11496
|
* @copyright 2025 Roman Barinov <rbarinov@gmail.com>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiflis-io/tiflis-code-workstation",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.13",
|
|
4
4
|
"description": "Workstation server for tiflis-code - manages agent sessions and terminal access",
|
|
5
5
|
"author": "Roman Barinov <rbarinov@gmail.com>",
|
|
6
6
|
"license": "FSL-1.1-NC",
|