zerg-ztc 0.1.3 → 0.1.4

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.
Files changed (72) hide show
  1. package/dist/App.d.ts.map +1 -1
  2. package/dist/App.js +71 -13
  3. package/dist/App.js.map +1 -1
  4. package/dist/agent/agent.d.ts.map +1 -1
  5. package/dist/agent/agent.js +3 -1
  6. package/dist/agent/agent.js.map +1 -1
  7. package/dist/agent/commands/index.d.ts.map +1 -1
  8. package/dist/agent/commands/index.js +3 -1
  9. package/dist/agent/commands/index.js.map +1 -1
  10. package/dist/agent/commands/input_mode.d.ts +3 -0
  11. package/dist/agent/commands/input_mode.d.ts.map +1 -0
  12. package/dist/agent/commands/input_mode.js +21 -0
  13. package/dist/agent/commands/input_mode.js.map +1 -0
  14. package/dist/agent/commands/keybindings.d.ts +3 -0
  15. package/dist/agent/commands/keybindings.d.ts.map +1 -0
  16. package/dist/agent/commands/keybindings.js +38 -0
  17. package/dist/agent/commands/keybindings.js.map +1 -0
  18. package/dist/agent/commands/types.d.ts +2 -0
  19. package/dist/agent/commands/types.d.ts.map +1 -1
  20. package/dist/cli.js +38 -1
  21. package/dist/cli.js.map +1 -1
  22. package/dist/components/FullScreen.d.ts.map +1 -1
  23. package/dist/components/FullScreen.js +29 -29
  24. package/dist/components/FullScreen.js.map +1 -1
  25. package/dist/components/InputArea.d.ts.map +1 -1
  26. package/dist/components/InputArea.js +476 -19
  27. package/dist/components/InputArea.js.map +1 -1
  28. package/dist/components/StatusBar.d.ts +1 -0
  29. package/dist/components/StatusBar.d.ts.map +1 -1
  30. package/dist/components/StatusBar.js +2 -1
  31. package/dist/components/StatusBar.js.map +1 -1
  32. package/dist/types.d.ts +1 -0
  33. package/dist/types.d.ts.map +1 -1
  34. package/dist/ui/core/input_segments.d.ts +1 -0
  35. package/dist/ui/core/input_segments.d.ts.map +1 -1
  36. package/dist/ui/core/input_segments.js +46 -14
  37. package/dist/ui/core/input_segments.js.map +1 -1
  38. package/dist/ui/core/types.d.ts +1 -0
  39. package/dist/ui/core/types.d.ts.map +1 -1
  40. package/dist/ui/ink/render.d.ts +3 -1
  41. package/dist/ui/ink/render.d.ts.map +1 -1
  42. package/dist/ui/ink/render.js +7 -5
  43. package/dist/ui/ink/render.js.map +1 -1
  44. package/dist/ui/views/app.d.ts +2 -1
  45. package/dist/ui/views/app.d.ts.map +1 -1
  46. package/dist/ui/views/app.js +2 -1
  47. package/dist/ui/views/app.js.map +1 -1
  48. package/dist/ui/views/header.d.ts.map +1 -1
  49. package/dist/ui/views/header.js +8 -5
  50. package/dist/ui/views/header.js.map +1 -1
  51. package/dist/ui/views/status_bar.d.ts +2 -1
  52. package/dist/ui/views/status_bar.d.ts.map +1 -1
  53. package/dist/ui/views/status_bar.js +5 -1
  54. package/dist/ui/views/status_bar.js.map +1 -1
  55. package/package.json +1 -1
  56. package/src/App.tsx +71 -13
  57. package/src/agent/agent.ts +3 -1
  58. package/src/agent/commands/index.ts +4 -0
  59. package/src/agent/commands/input_mode.ts +22 -0
  60. package/src/agent/commands/keybindings.ts +40 -0
  61. package/src/agent/commands/types.ts +2 -0
  62. package/src/cli.tsx +43 -1
  63. package/src/components/FullScreen.tsx +39 -34
  64. package/src/components/InputArea.tsx +489 -19
  65. package/src/components/StatusBar.tsx +3 -0
  66. package/src/types.ts +1 -0
  67. package/src/ui/core/input_segments.ts +49 -14
  68. package/src/ui/core/types.ts +1 -0
  69. package/src/ui/ink/render.tsx +16 -5
  70. package/src/ui/views/app.ts +3 -0
  71. package/src/ui/views/header.ts +8 -5
  72. package/src/ui/views/status_bar.ts +6 -0
@@ -1,12 +1,12 @@
1
1
  import { box, text } from '../core/index.js';
2
2
  export function buildHeaderView({ title = 'Zerg Terminal Client', version = '0.1.0', dateLabel, showHelp = true, debug = false }) {
3
+ // Single-row header to minimize vertical space
3
4
  return box([
4
5
  box([
5
6
  text(title, { bold: true }),
7
+ text(' ', {}),
6
8
  text('ZTC', { color: 'gray', dimColor: true })
7
- ], {
8
- flexDirection: 'column'
9
- }),
9
+ ], { flexDirection: 'row' }),
10
10
  showHelp
11
11
  ? box([
12
12
  dateLabel ? text(dateLabel, { color: 'gray', dimColor: true }) : text('', {}),
@@ -19,10 +19,13 @@ export function buildHeaderView({ title = 'Zerg Terminal Client', version = '0.1
19
19
  ], { flexDirection: 'row' })
20
20
  : box([], { flexDirection: 'row' })
21
21
  ], {
22
- flexDirection: 'column',
22
+ flexDirection: 'row',
23
23
  justifyContent: 'space-between',
24
24
  paddingX: 1,
25
- paddingY: 1
25
+ height: 1,
26
+ flexShrink: 0,
27
+ borderStyle: debug ? 'single' : undefined,
28
+ borderColor: debug ? 'cyan' : undefined
26
29
  });
27
30
  }
28
31
  //# sourceMappingURL=header.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"header.js","sourceRoot":"","sources":["../../../src/ui/views/header.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAc,MAAM,kBAAkB,CAAC;AAUzD,MAAM,UAAU,eAAe,CAAC,EAC9B,KAAK,GAAG,sBAAsB,EAC9B,OAAO,GAAG,OAAO,EACjB,SAAS,EACT,QAAQ,GAAG,IAAI,EACf,KAAK,GAAG,KAAK,EACD;IACZ,OAAO,GAAG,CAAC;QACT,GAAG,CAAC;YACF,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;YAC3B,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;SAC/C,EAAE;YACD,aAAa,EAAE,QAAQ;SACxB,CAAC;QACF,QAAQ;YACN,CAAC,CAAC,GAAG,CAAC;gBACF,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC;gBAC7E,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC;gBACzE,IAAI,CAAC,IAAI,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;gBACtD,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;gBAC9C,IAAI,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;gBACtD,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;gBAC9C,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;aACjD,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;YAC9B,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;KACtC,EAAE;QACD,aAAa,EAAE,QAAQ;QACvB,cAAc,EAAE,eAAe;QAC/B,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,CAAC;KACZ,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"header.js","sourceRoot":"","sources":["../../../src/ui/views/header.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAc,MAAM,kBAAkB,CAAC;AAUzD,MAAM,UAAU,eAAe,CAAC,EAC9B,KAAK,GAAG,sBAAsB,EAC9B,OAAO,GAAG,OAAO,EACjB,SAAS,EACT,QAAQ,GAAG,IAAI,EACf,KAAK,GAAG,KAAK,EACD;IACZ,+CAA+C;IAC/C,OAAO,GAAG,CAAC;QACT,GAAG,CAAC;YACF,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;YAC3B,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YACb,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;SAC/C,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;QAC5B,QAAQ;YACN,CAAC,CAAC,GAAG,CAAC;gBACF,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC;gBAC7E,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC;gBACzE,IAAI,CAAC,IAAI,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;gBACtD,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;gBAC9C,IAAI,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;gBACtD,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;gBAC9C,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;aACjD,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;YAC9B,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;KACtC,EAAE;QACD,aAAa,EAAE,KAAK;QACpB,cAAc,EAAE,eAAe;QAC/B,QAAQ,EAAE,CAAC;QACX,MAAM,EAAE,CAAC;QACT,UAAU,EAAE,CAAC;QACb,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;QACzC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;KACxC,CAAC,CAAC;AACL,CAAC"}
@@ -10,9 +10,10 @@ interface StatusBarProps {
10
10
  provider?: string;
11
11
  model?: string;
12
12
  emulationId?: string;
13
+ inputMode?: 'queue' | 'interrupt';
13
14
  toast?: string | null;
14
15
  debug?: boolean;
15
16
  }
16
- export declare function buildStatusBarView({ state, sessionId, version, connectionStatus, contextLength, contextEstimated, provider, model, emulationId, toast, debug }: StatusBarProps): LayoutNode;
17
+ export declare function buildStatusBarView({ state, sessionId, version, connectionStatus, contextLength, contextEstimated, provider, model, emulationId, inputMode, toast, debug }: StatusBarProps): LayoutNode;
17
18
  export {};
18
19
  //# sourceMappingURL=status_bar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"status_bar.d.ts","sourceRoot":"","sources":["../../../src/ui/views/status_bar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAe,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAa,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEzD,UAAU,cAAc;IACtB,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,WAAW,GAAG,cAAc,GAAG,YAAY,CAAC;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAaD,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,SAAS,EACT,OAAiB,EACjB,gBAA8B,EAC9B,aAAa,EACb,gBAAgB,EAChB,QAAQ,EACR,KAAK,EACL,WAAW,EACX,KAAK,EACL,KAAa,EACd,EAAE,cAAc,GAAG,UAAU,CA+D7B"}
1
+ {"version":3,"file":"status_bar.d.ts","sourceRoot":"","sources":["../../../src/ui/views/status_bar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAe,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAa,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEzD,UAAU,cAAc;IACtB,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,WAAW,GAAG,cAAc,GAAG,YAAY,CAAC;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAaD,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,SAAS,EACT,OAAiB,EACjB,gBAA8B,EAC9B,aAAa,EACb,gBAAgB,EAChB,QAAQ,EACR,KAAK,EACL,WAAW,EACX,SAAS,EACT,KAAK,EACL,KAAa,EACd,EAAE,cAAc,GAAG,UAAU,CAmE7B"}
@@ -9,7 +9,7 @@ function getStatusConfig(state) {
9
9
  };
10
10
  return configs[state.status];
11
11
  }
12
- export function buildStatusBarView({ state, sessionId, version = '0.1.0', connectionStatus = 'connected', contextLength, contextEstimated, provider, model, emulationId, toast, debug = false }) {
12
+ export function buildStatusBarView({ state, sessionId, version = '0.1.0', connectionStatus = 'connected', contextLength, contextEstimated, provider, model, emulationId, inputMode, toast, debug = false }) {
13
13
  const config = getStatusConfig(state);
14
14
  const isActive = state.status !== 'idle' && state.status !== 'error';
15
15
  const connectionColors = {
@@ -45,6 +45,8 @@ export function buildStatusBarView({ state, sessionId, version = '0.1.0', connec
45
45
  (provider || model) ? text(' • ', { color: 'gray', dimColor: true }) : text('', {}),
46
46
  emulationId ? text(`emu:${emulationId}`, { color: 'gray', dimColor: true }) : text('', {}),
47
47
  emulationId ? text(' • ', { color: 'gray', dimColor: true }) : text('', {}),
48
+ inputMode ? text(`mode:${inputMode}`, { color: 'gray', dimColor: true }) : text('', {}),
49
+ inputMode ? text(' • ', { color: 'gray', dimColor: true }) : text('', {}),
48
50
  state.tokensUsed !== undefined && state.tokensUsed > 0
49
51
  ? text(`${state.tokensUsed.toLocaleString()} tok`, { color: 'gray', dimColor: true })
50
52
  : text('', {}),
@@ -65,6 +67,8 @@ export function buildStatusBarView({ state, sessionId, version = '0.1.0', connec
65
67
  flexDirection: 'row',
66
68
  justifyContent: 'space-between',
67
69
  paddingX: 1,
70
+ height: 1,
71
+ flexShrink: 0,
68
72
  borderStyle: debug ? 'single' : undefined,
69
73
  borderColor: debug ? 'gray' : undefined
70
74
  });
@@ -1 +1 @@
1
- {"version":3,"file":"status_bar.js","sourceRoot":"","sources":["../../../src/ui/views/status_bar.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"status_bar.js","sourceRoot":"","sources":["../../../src/ui/views/status_bar.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zerg-ztc",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Zerg Terminal Client - CLI agent for continual AI systems",
5
5
  "type": "module",
6
6
  "bin": {
package/src/App.tsx CHANGED
@@ -5,7 +5,7 @@ import { buildAppView } from './ui/views/app.js';
5
5
  import { useMirror } from './web/mirror_hook.js';
6
6
  import { Agent } from './agent/index.js';
7
7
  import { commands, type CommandContext } from './agent/commands/index.js';
8
- import { Message, AgentState } from './types.js';
8
+ import { Message, AgentState, InputMode } from './types.js';
9
9
  import { InputState } from './ui/core/input_state.js';
10
10
  import { configStore } from './config.js';
11
11
  import { createInputBus } from './ui/core/input.js';
@@ -68,11 +68,16 @@ export const App: React.FC = () => {
68
68
 
69
69
  // State
70
70
  const [messages, setMessages] = useState<Message[]>([getWelcomeMessage()]);
71
+ const messagesRef = useRef<Message[]>(messages);
71
72
  const [agentState, setAgentState] = useState<AgentState>({ status: 'idle' });
72
73
  const [sessionId] = useState(generateId());
73
74
  const [agent, setAgent] = useState<Agent | null>(createAgent);
74
75
  const [expandToolOutputs, setExpandToolOutputs] = useState(false);
75
76
  const [skills, setSkills] = useState<Skill[]>([]);
77
+ const [inputMode, setInputMode] = useState<InputMode>('queue');
78
+ const queueRef = useRef<string[]>([]);
79
+ const activeRunIdRef = useRef<string | null>(null);
80
+ const runCounterRef = useRef(0);
76
81
 
77
82
  React.useEffect(() => {
78
83
  let active = true;
@@ -117,6 +122,9 @@ export const App: React.FC = () => {
117
122
  renderCount.current += 1;
118
123
  debugLog(`App render #${renderCount.current} (messages=${messages.length}, state=${agentState.status})`);
119
124
  });
125
+ React.useEffect(() => {
126
+ messagesRef.current = messages;
127
+ }, [messages]);
120
128
  const [debug, setDebug] = useState(false);
121
129
 
122
130
  const inputHeight = 5; // 1 input line + 4 suggestion lines
@@ -193,15 +201,22 @@ export const App: React.FC = () => {
193
201
  return lower.includes('overloaded') || lower.includes('529') || lower.includes('429') || lower.includes('rate limit');
194
202
  }, []);
195
203
 
196
- const runWithRetry = useCallback(async (requestMessages: Message[], runAgent: Agent, isManual = false) => {
204
+ const runWithRetry = useCallback(async (
205
+ requestMessages: Message[],
206
+ runAgent: Agent,
207
+ isManual = false,
208
+ isActive?: () => boolean
209
+ ) => {
197
210
  const maxRetries = 3;
198
211
  let attempt = 0;
199
212
  setRetryAvailable(false);
200
213
  while (attempt < maxRetries) {
201
214
  attempt += 1;
215
+ if (isActive && !isActive()) return;
202
216
  try {
203
217
  streamedResponse.current = false;
204
218
  const result = await runAgent.run(requestMessages);
219
+ if (isActive && !isActive()) return;
205
220
  if (!streamedResponse.current) {
206
221
  addMessage({
207
222
  role: 'assistant',
@@ -220,6 +235,7 @@ export const App: React.FC = () => {
220
235
  return;
221
236
  } catch (err) {
222
237
  const errorMsg = (err as Error).message || 'Agent error';
238
+ if (isActive && !isActive()) return;
223
239
  if (!isRetryableError(errorMsg) || attempt >= maxRetries) {
224
240
  throw err;
225
241
  }
@@ -242,9 +258,13 @@ export const App: React.FC = () => {
242
258
  addMessage({ role: 'system', content: 'No previous request to retry.' });
243
259
  return;
244
260
  }
261
+ const runId = `${Date.now()}_${runCounterRef.current++}`;
262
+ activeRunIdRef.current = runId;
263
+ const isActive = () => activeRunIdRef.current === runId;
245
264
  setAgentState({ status: 'thinking', startedAt: new Date() });
246
- void runWithRetry(last.messages, last.agent, true).catch((err) => {
265
+ void runWithRetry(last.messages, last.agent, true, isActive).catch((err) => {
247
266
  const message = (err as Error).message || 'Agent error';
267
+ if (!isActive()) return;
248
268
  addMessage({ role: 'system', content: `Error: ${message}` });
249
269
  if (isRetryableError(message)) {
250
270
  addMessage({ role: 'system', content: 'Retries exhausted. Use /retry to try again.' });
@@ -282,8 +302,10 @@ export const App: React.FC = () => {
282
302
  },
283
303
  skills: {
284
304
  list: async () => getSkillRegistry()
285
- }
286
- }), [addMessage, clearMessages, getMessages, reloadAgent, exit, shellController, retryLast]);
305
+ },
306
+ getInputMode: () => inputMode,
307
+ setInputMode: (mode) => setInputMode(mode)
308
+ }), [addMessage, clearMessages, getMessages, reloadAgent, exit, shellController, retryLast, inputMode]);
287
309
 
288
310
  // Handle commands
289
311
  const handleCommand = useCallback((cmd: string, args: string[]) => {
@@ -322,6 +344,22 @@ export const App: React.FC = () => {
322
344
  return;
323
345
  }
324
346
 
347
+ const busy = agentState.status !== 'idle' && agentState.status !== 'error';
348
+ if (busy) {
349
+ if (inputMode === 'queue') {
350
+ queueRef.current.push(text);
351
+ addMessage({
352
+ role: 'system',
353
+ content: `Queued (${queueRef.current.length})`
354
+ });
355
+ return;
356
+ }
357
+ addMessage({
358
+ role: 'system',
359
+ content: 'Interrupting current response...'
360
+ });
361
+ }
362
+
325
363
  let currentAgent = agent;
326
364
 
327
365
  if (skills.length > 0) {
@@ -373,12 +411,18 @@ export const App: React.FC = () => {
373
411
  timestamp: new Date()
374
412
  };
375
413
  setMessages(prev => [...prev, userMsg]);
376
- const requestMessages = [...messages, userMsg];
414
+ const requestMessages = [...messagesRef.current, userMsg];
377
415
  lastRequestRef.current = { messages: requestMessages, agent: currentAgent };
378
416
 
417
+ const runId = `${Date.now()}_${runCounterRef.current++}`;
418
+ activeRunIdRef.current = runId;
419
+ const isActive = () => activeRunIdRef.current === runId;
379
420
  setAgentState({ status: 'thinking', startedAt: new Date() });
421
+ streamingMessageId.current = null;
422
+ streamedResponse.current = false;
380
423
 
381
424
  const cleanup = currentAgent.on((event) => {
425
+ if (!isActive()) return;
382
426
  switch (event.type) {
383
427
  case 'thinking_start':
384
428
  setAgentState(s => ({ ...s, status: 'thinking' }));
@@ -475,9 +519,10 @@ export const App: React.FC = () => {
475
519
  });
476
520
 
477
521
  try {
478
- await runWithRetry(requestMessages, currentAgent);
522
+ await runWithRetry(requestMessages, currentAgent, false, isActive);
479
523
  } catch (err) {
480
524
  const errorMsg = (err as Error).message;
525
+ if (!isActive()) return;
481
526
 
482
527
  const isAuthError = errorMsg.includes('401') || errorMsg.includes('authentication');
483
528
  if (isAuthError) {
@@ -504,11 +549,22 @@ export const App: React.FC = () => {
504
549
  setAgentState({ status: 'idle' });
505
550
  }, 3000);
506
551
  } finally {
507
- streamedResponse.current = false;
508
- streamingMessageId.current = null;
509
- cleanup();
552
+ if (isActive()) {
553
+ streamedResponse.current = false;
554
+ streamingMessageId.current = null;
555
+ activeRunIdRef.current = null;
556
+ cleanup();
557
+ if (inputMode === 'queue' && queueRef.current.length > 0) {
558
+ const next = queueRef.current.shift();
559
+ if (next) {
560
+ void handleSubmit(next);
561
+ }
562
+ }
563
+ } else {
564
+ cleanup();
565
+ }
510
566
  }
511
- }, [messages, agent, addMessage, isRetryableError, runWithRetry]);
567
+ }, [agent, agentState.status, addMessage, handleCommand, inputMode, isRetryableError, runWithRetry]);
512
568
 
513
569
  const layoutTree = useMemo(() => {
514
570
  if (!mirrorEnabled) return null;
@@ -526,11 +582,12 @@ export const App: React.FC = () => {
526
582
  provider,
527
583
  model,
528
584
  emulationId,
585
+ inputMode,
529
586
  toast,
530
587
  debug,
531
588
  expandToolOutputs
532
589
  });
533
- }, [mirrorEnabled, messages, agentState, inputSnapshot, sessionId, rows, contextLength, contextEstimated, provider, model, emulationId, toast, debug, expandToolOutputs]);
590
+ }, [mirrorEnabled, messages, agentState, inputSnapshot, sessionId, rows, contextLength, contextEstimated, provider, model, emulationId, inputMode, toast, debug, expandToolOutputs]);
534
591
 
535
592
  const showToast = useCallback((message: string) => {
536
593
  setToast(message);
@@ -563,7 +620,7 @@ export const App: React.FC = () => {
563
620
  onToast={showToast}
564
621
  cols={columns}
565
622
  inputBus={inputBus}
566
- disabled={agentState.status !== 'idle' && agentState.status !== 'error'}
623
+ disabled={false}
567
624
  debug={debug}
568
625
  placeholder={
569
626
  !configStore.hasApiKey() ? 'Set API key with /config key <key>' :
@@ -584,6 +641,7 @@ export const App: React.FC = () => {
584
641
  provider={provider}
585
642
  model={model}
586
643
  emulationId={emulationId}
644
+ inputMode={inputMode}
587
645
  toast={toast}
588
646
  debug={debug}
589
647
  />
@@ -77,7 +77,9 @@ You have access to tools for:
77
77
  - Running shell commands
78
78
  - Querying the Zerg system
79
79
 
80
- Be concise and helpful. When using tools, explain what you're doing briefly. If a task requires multiple steps, proceed through them systematically.`;
80
+ Be concise and helpful. When using tools, explain what you're doing briefly. If a task requires multiple steps, proceed through them systematically.
81
+
82
+ When a user intent maps to an available slash command, invoke the command directly (just the command) instead of explaining how to do it. Prefer executing commands over describing them.`;
81
83
  }
82
84
 
83
85
  // Event handling
@@ -12,6 +12,8 @@ import { modelCommand } from './model.js';
12
12
  import { permissionsCommand } from './permissions.js';
13
13
  import { skillsCommand } from './skills.js';
14
14
  import { retryCommand } from './retry.js';
15
+ import { inputModeCommand } from './input_mode.js';
16
+ import { keybindingsCommand } from './keybindings.js';
15
17
  import { Command } from './types.js';
16
18
 
17
19
  const commandList: Command[] = [];
@@ -32,6 +34,8 @@ commandList.push(
32
34
  modelCommand,
33
35
  permissionsCommand,
34
36
  skillsCommand,
37
+ keybindingsCommand,
38
+ inputModeCommand,
35
39
  retryCommand,
36
40
  exitCommand
37
41
  );
@@ -0,0 +1,22 @@
1
+ import { Command } from './types.js';
2
+
3
+ export const inputModeCommand: Command = {
4
+ name: 'inputmode',
5
+ description: 'Set input mode while an agent is running',
6
+ usage: '<queue|interrupt>',
7
+ handler: (args, ctx) => {
8
+ const mode = (args[0] || '').toLowerCase();
9
+ if (mode !== 'queue' && mode !== 'interrupt') {
10
+ ctx.addMessage({
11
+ role: 'system',
12
+ content: `Current input mode: ${ctx.getInputMode()}\n\nUsage: /inputmode <queue|interrupt>`
13
+ });
14
+ return;
15
+ }
16
+ ctx.setInputMode(mode);
17
+ ctx.addMessage({
18
+ role: 'system',
19
+ content: `✓ Input mode set: ${mode}`
20
+ });
21
+ }
22
+ };
@@ -0,0 +1,40 @@
1
+ import { Command } from './types.js';
2
+
3
+ const lines = [
4
+ 'Keybindings (readline-style):',
5
+ '',
6
+ 'Movement:',
7
+ ' Ctrl+A start of line',
8
+ ' Ctrl+E end of line',
9
+ ' Ctrl+B move left',
10
+ ' Ctrl+F move right',
11
+ ' Alt+B word left',
12
+ ' Alt+F word right',
13
+ '',
14
+ 'Editing:',
15
+ ' Ctrl+U kill to start',
16
+ ' Ctrl+K kill to end',
17
+ ' Ctrl+W kill previous word',
18
+ ' Alt+D kill next word',
19
+ ' Ctrl+D delete forward',
20
+ ' Ctrl+Y yank',
21
+ ' Alt+Y yank-pop',
22
+ ' Ctrl+T transpose chars',
23
+ ' Alt+T transpose words',
24
+ '',
25
+ 'History:',
26
+ ' Ctrl+P previous',
27
+ ' Ctrl+N next',
28
+ ' Up/Down arrows also work',
29
+ '',
30
+ 'Input mode:',
31
+ ' /inputmode queue|interrupt'
32
+ ];
33
+
34
+ export const keybindingsCommand: Command = {
35
+ name: 'keybindings',
36
+ description: 'Show keybindings',
37
+ handler: (_args, ctx) => {
38
+ ctx.addMessage({ role: 'system', content: lines.join('\n') });
39
+ }
40
+ };
@@ -68,6 +68,8 @@ export interface CommandContext {
68
68
  clipboard: ClipboardController;
69
69
  models: ModelsController;
70
70
  skills: SkillsController;
71
+ getInputMode: () => 'queue' | 'interrupt';
72
+ setInputMode: (mode: 'queue' | 'interrupt') => void;
71
73
  }
72
74
 
73
75
  export interface Command {
package/src/cli.tsx CHANGED
@@ -75,12 +75,54 @@ if (cwdIndex >= 0) {
75
75
  async function main(): Promise<void> {
76
76
  await configStore.load(true);
77
77
 
78
+ const isTty = Boolean(process.stdout.isTTY);
79
+ const useAltScreen = isTty && process.env.ZTC_ALT_SCREEN !== '0' && process.env.ZTC_NO_ALT_SCREEN !== '1';
80
+
81
+ if (useAltScreen) {
82
+ process.stdout.write('\x1b[?1049h');
83
+ process.stdout.write('\x1b[?25l');
84
+ process.stdout.write('\x1b[2J');
85
+ process.stdout.write('\x1b[H');
86
+ }
87
+
88
+ // Enable bracketed paste mode so we can detect paste boundaries
89
+ process.stdout.write('\x1b[?2004h');
90
+
91
+ // Enable Kitty keyboard protocol (progressive enhancement)
92
+ // This allows detection of Cmd+V and other modifier combinations
93
+ // Flags: 1 = disambiguate escape codes, 2 = report event types, 4 = report alternate keys, 8 = report all keys
94
+ // Using flags=1 for basic disambiguation which reports Cmd+V as CSI sequence
95
+ process.stdout.write('\x1b[>1u');
96
+
97
+ // Wrap stdout.write to use synchronized output (reduces flicker)
98
+ // DECSM/DECRM 2026 tells terminal to batch updates
99
+ const originalWrite = process.stdout.write.bind(process.stdout);
100
+ let syncPending = false;
101
+ process.stdout.write = function(chunk: any, encoding?: any, callback?: any): boolean {
102
+ if (!syncPending) {
103
+ syncPending = true;
104
+ originalWrite('\x1b[?2026h'); // Begin synchronized update
105
+ setImmediate(() => {
106
+ originalWrite('\x1b[?2026l'); // End synchronized update
107
+ syncPending = false;
108
+ });
109
+ }
110
+ return originalWrite(chunk, encoding, callback);
111
+ } as typeof process.stdout.write;
112
+
78
113
  // Render the app
79
- // Note: FullScreen component handles alternate screen buffer
80
114
  const { waitUntilExit } = render(<App />);
81
115
 
82
116
  // Handle clean exit
83
117
  waitUntilExit().then(() => {
118
+ // Disable Kitty keyboard protocol
119
+ process.stdout.write('\x1b[<u');
120
+ // Disable bracketed paste mode
121
+ process.stdout.write('\x1b[?2004l');
122
+ if (useAltScreen) {
123
+ process.stdout.write('\x1b[?25h');
124
+ process.stdout.write('\x1b[?1049l');
125
+ }
84
126
  console.log('Goodbye from ZTC! 👋');
85
127
  process.exit(0);
86
128
  });
@@ -1,14 +1,14 @@
1
- import React, { useEffect, PropsWithChildren } from 'react';
1
+ import React, { PropsWithChildren, useState, useEffect } from 'react';
2
2
  import { Box } from 'ink';
3
3
 
4
4
  /**
5
5
  * FullScreen component that uses the alternate screen buffer.
6
- *
6
+ *
7
7
  * This prevents flickering by:
8
8
  * 1. Switching to the alternate screen buffer (like vim, htop, less do)
9
9
  * 2. Tracking terminal resize events
10
10
  * 3. Restoring the original terminal state on exit
11
- *
11
+ *
12
12
  * ANSI escape codes:
13
13
  * - \x1b[?1049h - Enter alternate screen buffer
14
14
  * - \x1b[?1049l - Exit alternate screen buffer
@@ -20,41 +20,22 @@ interface FullScreenProps extends PropsWithChildren {
20
20
  debug?: boolean;
21
21
  }
22
22
 
23
- const initialSize = {
24
- columns: process.stdout.columns || 80,
25
- rows: process.stdout.rows || 24,
26
- };
23
+ function getTerminalSize() {
24
+ return {
25
+ columns: process.stdout.columns || 80,
26
+ rows: process.stdout.rows || 24,
27
+ };
28
+ }
27
29
 
28
30
  export const FullScreen: React.FC<FullScreenProps> = ({ children, debug = false }) => {
29
- const isTty = Boolean(process.stdout.isTTY);
30
- const useAltScreen = isTty && process.env.ZTC_ALT_SCREEN === '1';
31
-
32
- useEffect(() => {
33
- if (!useAltScreen) {
34
- return;
35
- }
36
-
37
- // Enter alternate screen buffer
38
- process.stdout.write('\x1b[?1049h');
39
- // Hide cursor (we'll draw our own)
40
- process.stdout.write('\x1b[?25l');
41
- // Clear the alternate screen
42
- process.stdout.write('\x1b[2J');
43
- // Move cursor to top-left
44
- process.stdout.write('\x1b[H');
45
-
46
- // Cleanup: restore terminal state
47
- return () => {
48
- // Show cursor
49
- process.stdout.write('\x1b[?25h');
50
- // Exit alternate screen buffer (restores original content)
51
- process.stdout.write('\x1b[?1049l');
52
- };
53
- }, [useAltScreen]);
31
+ const { rows, columns } = useScreenSize();
54
32
 
55
33
  return (
56
- <Box
34
+ <Box
57
35
  flexDirection="column"
36
+ width={columns}
37
+ height={rows}
38
+ overflow="hidden"
58
39
  borderStyle={debug ? 'single' : undefined}
59
40
  borderColor={debug ? 'red' : undefined}
60
41
  >
@@ -67,7 +48,31 @@ export const FullScreen: React.FC<FullScreenProps> = ({ children, debug = false
67
48
  * Hook to get current screen size with resize tracking
68
49
  */
69
50
  export function useScreenSize() {
70
- return initialSize;
51
+ const [size, setSize] = useState(getTerminalSize);
52
+
53
+ useEffect(() => {
54
+ const updateSize = () => {
55
+ const current = getTerminalSize();
56
+ setSize(prev => {
57
+ if (prev.rows !== current.rows || prev.columns !== current.columns) {
58
+ return current;
59
+ }
60
+ return prev;
61
+ });
62
+ };
63
+
64
+ process.stdout.on('resize', updateSize);
65
+
66
+ // Also check on an interval as a fallback for some terminals
67
+ const interval = setInterval(updateSize, 1000);
68
+
69
+ return () => {
70
+ process.stdout.off('resize', updateSize);
71
+ clearInterval(interval);
72
+ };
73
+ }, []);
74
+
75
+ return size;
71
76
  }
72
77
 
73
78
  export default FullScreen;