mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-04 22:49:41 +02:00
chore: bump version to 0.1567
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+12
-5
@@ -958,8 +958,8 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
||||
*
|
||||
* Uses tmux send-keys for reliable input delivery:
|
||||
* - `-l` flag sends literal text (no key interpretation)
|
||||
* - `Enter` key is sent as a separate argument
|
||||
* - Single command, no delay needed
|
||||
* - `Enter` key is sent as a SEPARATE tmux invocation after a small delay
|
||||
* - Ink (Claude CLI) needs text and Enter split to avoid treating Enter as a newline
|
||||
*/
|
||||
async sendInput(sessionId: string, input: string): Promise<boolean> {
|
||||
const session = this.sessions.get(sessionId);
|
||||
@@ -985,10 +985,17 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
||||
const textPart = input.replace(/\r/g, '').replace(/\n/g, '').trimEnd();
|
||||
|
||||
if (textPart && hasCarriageReturn) {
|
||||
// Send text + Enter in a single tmux invocation (one child process).
|
||||
// tmux's \; separator chains commands within one process spawn.
|
||||
// Send text first, then Enter as a SEPARATE tmux command after a short delay.
|
||||
// Ink (Claude CLI's terminal framework) needs them split — sending both in a
|
||||
// single tmux invocation (via \;) causes Ink to interpret Enter as a newline
|
||||
// character in the input buffer rather than as form submission.
|
||||
await execAsync(
|
||||
`tmux send-keys -t "${session.muxName}" -l ${shellescape(textPart)} \\; send-keys -t "${session.muxName}" Enter`,
|
||||
`tmux send-keys -t "${session.muxName}" -l ${shellescape(textPart)}`,
|
||||
{ timeout: EXEC_TIMEOUT_MS }
|
||||
);
|
||||
await new Promise(resolve => setTimeout(resolve, 50));
|
||||
await execAsync(
|
||||
`tmux send-keys -t "${session.muxName}" Enter`,
|
||||
{ timeout: EXEC_TIMEOUT_MS }
|
||||
);
|
||||
} else if (textPart) {
|
||||
|
||||
+47
-17
@@ -48,13 +48,14 @@ const BUILTIN_RESPAWN_PRESETS = [
|
||||
{
|
||||
id: 'solo-work',
|
||||
name: 'Solo',
|
||||
description: 'Claude working alone — fast respawn cycles',
|
||||
description: 'Claude working alone — fast respawn cycles with context reset',
|
||||
config: {
|
||||
idleTimeoutMs: 3000,
|
||||
updatePrompt: 'continue',
|
||||
updatePrompt: 'summarize your progress so far before the context reset.',
|
||||
interStepDelayMs: 2000,
|
||||
sendClear: false,
|
||||
sendInit: false,
|
||||
sendClear: true,
|
||||
sendInit: true,
|
||||
kickstartPrompt: 'continue working. Pick up where you left off based on the context above.',
|
||||
autoAcceptPrompts: true,
|
||||
},
|
||||
durationMinutes: 60,
|
||||
@@ -67,10 +68,11 @@ const BUILTIN_RESPAWN_PRESETS = [
|
||||
description: 'Lead session with Task tool subagents — longer idle tolerance',
|
||||
config: {
|
||||
idleTimeoutMs: 45000,
|
||||
updatePrompt: 'check on your running subagents and continue coordinating their work. If all subagents have finished, summarize their results and proceed with the next step.',
|
||||
updatePrompt: 'check on your running subagents and summarize their results before the context reset. If all subagents have finished, note what was completed and what remains.',
|
||||
interStepDelayMs: 3000,
|
||||
sendClear: false,
|
||||
sendInit: false,
|
||||
sendClear: true,
|
||||
sendInit: true,
|
||||
kickstartPrompt: 'check on your running subagents and continue coordinating their work. If all subagents have finished, summarize their results and proceed with the next step.',
|
||||
autoAcceptPrompts: true,
|
||||
},
|
||||
durationMinutes: 240,
|
||||
@@ -83,10 +85,11 @@ const BUILTIN_RESPAWN_PRESETS = [
|
||||
description: 'Leading an agent team via TeamCreate — tolerates long silences',
|
||||
config: {
|
||||
idleTimeoutMs: 90000,
|
||||
updatePrompt: 'check on your teammates by reviewing the task list and any messages in your inbox. Assign new tasks if teammates are idle, or continue coordinating the team effort.',
|
||||
updatePrompt: 'review the task list and teammate progress. Summarize the current state before the context reset.',
|
||||
interStepDelayMs: 5000,
|
||||
sendClear: false,
|
||||
sendInit: false,
|
||||
sendClear: true,
|
||||
sendInit: true,
|
||||
kickstartPrompt: 'check on your teammates by reviewing the task list and any messages in your inbox. Assign new tasks if teammates are idle, or continue coordinating the team effort.',
|
||||
autoAcceptPrompts: true,
|
||||
},
|
||||
durationMinutes: 480,
|
||||
@@ -922,10 +925,18 @@ class LocalEchoOverlay {
|
||||
}
|
||||
}
|
||||
|
||||
appendText(text) {
|
||||
if (!text) return;
|
||||
this.pendingText += text;
|
||||
this._persist();
|
||||
this._render();
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.pendingText = '';
|
||||
this._persist();
|
||||
this._lastRenderKey = '';
|
||||
this._lastPromptPos = null;
|
||||
this.overlay.innerHTML = '';
|
||||
this.overlay.style.display = 'none';
|
||||
}
|
||||
@@ -955,20 +966,26 @@ class LocalEchoOverlay {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// Re-scan for prompt on EVERY render — Ink can move it between redraws
|
||||
// Re-scan for prompt on EVERY render — Ink can move it between redraws.
|
||||
// Cache last known position as fallback during Ink redraw flicker.
|
||||
const prompt = this._findPrompt();
|
||||
if (!prompt) { this.overlay.style.display = 'none'; return; }
|
||||
if (prompt) {
|
||||
this._lastPromptPos = prompt;
|
||||
} else if (!this._lastPromptPos) {
|
||||
this.overlay.style.display = 'none'; return;
|
||||
}
|
||||
const activePrompt = this._lastPromptPos;
|
||||
|
||||
const dims = this.terminal._core._renderService.dimensions;
|
||||
const cellW = dims.css.cell.width;
|
||||
const cellH = dims.css.cell.height;
|
||||
const totalCols = this.terminal.cols;
|
||||
// Position right after "❯ " (prompt col + 2)
|
||||
const startCol = Math.min(prompt.col + 2, totalCols - 1);
|
||||
const startCol = Math.min(activePrompt.col + 2, totalCols - 1);
|
||||
const firstLineCols = Math.max(1, totalCols - startCol);
|
||||
|
||||
// Skip redundant re-renders (e.g. from flushPendingWrites at 60fps)
|
||||
const renderKey = `${this.pendingText.length}:${prompt.row}:${prompt.col}:${totalCols}`;
|
||||
const renderKey = `${this.pendingText.length}:${activePrompt.row}:${activePrompt.col}:${totalCols}`;
|
||||
if (renderKey === this._lastRenderKey && this.overlay.style.display !== 'none') return;
|
||||
this._lastRenderKey = renderKey;
|
||||
|
||||
@@ -986,7 +1003,7 @@ class LocalEchoOverlay {
|
||||
|
||||
// Position overlay container at prompt row
|
||||
this.overlay.style.left = '0px';
|
||||
this.overlay.style.top = (prompt.row * cellH) + 'px';
|
||||
this.overlay.style.top = (activePrompt.row * cellH) + 'px';
|
||||
this.overlay.style.boxShadow = 'none';
|
||||
|
||||
// Build line elements — recreate on each render (typically 1-3 divs, negligible cost)
|
||||
@@ -2075,8 +2092,21 @@ class ClaudemanApp {
|
||||
}, 120);
|
||||
return;
|
||||
}
|
||||
if (data.charCodeAt(0) < 32 || data.length > 1) {
|
||||
// Other control chars (Ctrl+C, escape, paste): clear overlay, drain bg, send immediately
|
||||
if (data.length > 1 && data.charCodeAt(0) >= 32) {
|
||||
// Paste: append to overlay + send to PTY immediately
|
||||
this._localEchoOverlay?.appendText(data);
|
||||
const remainder = drainBgBuffer();
|
||||
if (remainder) this._pendingInput += remainder;
|
||||
this._pendingInput += data;
|
||||
if (this._inputFlushTimeout) {
|
||||
clearTimeout(this._inputFlushTimeout);
|
||||
this._inputFlushTimeout = null;
|
||||
}
|
||||
flushInput();
|
||||
return;
|
||||
}
|
||||
if (data.charCodeAt(0) < 32) {
|
||||
// Control chars (Ctrl+C, escape sequences): clear overlay, drain bg, send immediately
|
||||
this._localEchoOverlay?.clear();
|
||||
const remainder = drainBgBuffer();
|
||||
if (remainder) {
|
||||
|
||||
@@ -780,6 +780,19 @@
|
||||
<!-- Display Tab -->
|
||||
<div class="modal-tab-content" id="settings-display">
|
||||
<div class="settings-grid">
|
||||
<!-- Input Section -->
|
||||
<div class="settings-section-header">Input</div>
|
||||
<div class="settings-item settings-item-multiline" title="Shows typed characters instantly via overlay while forwarding keystrokes to the server in the background. Enables Tab completion, preserves input across tab switches, and protects against session crashes. Recommended for mobile and high-latency connections.">
|
||||
<div class="settings-item-text">
|
||||
<span class="settings-item-label">Local Echo</span>
|
||||
<span class="settings-item-desc">Instant typing feedback with local echo</span>
|
||||
</div>
|
||||
<label class="switch switch-sm">
|
||||
<input type="checkbox" id="appSettingsLocalEcho">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Header Displays Section -->
|
||||
<div class="settings-section-header">Header Displays</div>
|
||||
<div class="settings-item" title="Show A-/A+ font size buttons in header">
|
||||
@@ -886,15 +899,6 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Input Options Section -->
|
||||
<div class="settings-section-header">Input</div>
|
||||
<div class="settings-item" title="Buffer keystrokes locally and show them instantly via overlay. Text is sent to the server on Enter. Useful for high-latency connections or to compose input before sending.">
|
||||
<span class="settings-item-label">Local Echo</span>
|
||||
<label class="switch switch-sm">
|
||||
<input type="checkbox" id="appSettingsLocalEcho">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2523,6 +2523,25 @@ body {
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.settings-item-multiline {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.settings-item-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.15rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.settings-item-desc {
|
||||
font-size: 0.6rem;
|
||||
color: var(--text-muted);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.settings-item-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user