cmdr-agent 2.4.0 → 2.5.1

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 (109) hide show
  1. package/dist/bin/cmdr.js +117 -27
  2. package/dist/bin/cmdr.js.map +1 -1
  3. package/dist/package.json +9 -4
  4. package/dist/src/cli/ink/App.d.ts +2 -2
  5. package/dist/src/cli/ink/App.d.ts.map +1 -1
  6. package/dist/src/cli/ink/App.js +118 -65
  7. package/dist/src/cli/ink/App.js.map +1 -1
  8. package/dist/src/cli/ink/PromptInput.d.ts +17 -0
  9. package/dist/src/cli/ink/PromptInput.d.ts.map +1 -0
  10. package/dist/src/cli/ink/PromptInput.js +202 -0
  11. package/dist/src/cli/ink/PromptInput.js.map +1 -0
  12. package/dist/src/cli/ink/StatusBar.d.ts +1 -1
  13. package/dist/src/cli/ink/StatusBar.d.ts.map +1 -1
  14. package/dist/src/cli/ink/StatusBar.js +116 -21
  15. package/dist/src/cli/ink/StatusBar.js.map +1 -1
  16. package/dist/src/cli/ink/input-buffer.d.ts +34 -0
  17. package/dist/src/cli/ink/input-buffer.d.ts.map +1 -0
  18. package/dist/src/cli/ink/input-buffer.js +152 -0
  19. package/dist/src/cli/ink/input-buffer.js.map +1 -0
  20. package/dist/src/cli/progress.d.ts +59 -0
  21. package/dist/src/cli/progress.d.ts.map +1 -0
  22. package/dist/src/cli/progress.js +172 -0
  23. package/dist/src/cli/progress.js.map +1 -0
  24. package/dist/src/cli/renderer.d.ts +14 -3
  25. package/dist/src/cli/renderer.d.ts.map +1 -1
  26. package/dist/src/cli/renderer.js +93 -32
  27. package/dist/src/cli/renderer.js.map +1 -1
  28. package/dist/src/cli/repl.d.ts.map +1 -1
  29. package/dist/src/cli/repl.js +46 -28
  30. package/dist/src/cli/repl.js.map +1 -1
  31. package/dist/src/cli/spinner.d.ts +4 -1
  32. package/dist/src/cli/spinner.d.ts.map +1 -1
  33. package/dist/src/cli/spinner.js +34 -1
  34. package/dist/src/cli/spinner.js.map +1 -1
  35. package/dist/src/cli/theme.d.ts +14 -12
  36. package/dist/src/cli/theme.d.ts.map +1 -1
  37. package/dist/src/cli/theme.js +192 -123
  38. package/dist/src/cli/theme.js.map +1 -1
  39. package/dist/src/cli/themes.d.ts +17 -1
  40. package/dist/src/cli/themes.d.ts.map +1 -1
  41. package/dist/src/cli/themes.js +125 -27
  42. package/dist/src/cli/themes.js.map +1 -1
  43. package/dist/src/core/agent-runner.d.ts +12 -0
  44. package/dist/src/core/agent-runner.d.ts.map +1 -1
  45. package/dist/src/core/agent-runner.js +176 -5
  46. package/dist/src/core/agent-runner.js.map +1 -1
  47. package/dist/src/core/event-bus.d.ts +12 -0
  48. package/dist/src/core/event-bus.d.ts.map +1 -1
  49. package/dist/src/core/event-bus.js.map +1 -1
  50. package/dist/src/core/presets.d.ts.map +1 -1
  51. package/dist/src/core/presets.js +1 -0
  52. package/dist/src/core/presets.js.map +1 -1
  53. package/dist/src/core/types.d.ts +17 -0
  54. package/dist/src/core/types.d.ts.map +1 -1
  55. package/dist/src/core/types.js +8 -1
  56. package/dist/src/core/types.js.map +1 -1
  57. package/dist/src/llm/anthropic.d.ts +1 -0
  58. package/dist/src/llm/anthropic.d.ts.map +1 -1
  59. package/dist/src/llm/anthropic.js +20 -1
  60. package/dist/src/llm/anthropic.js.map +1 -1
  61. package/dist/src/llm/ollama.d.ts +2 -12
  62. package/dist/src/llm/ollama.d.ts.map +1 -1
  63. package/dist/src/llm/ollama.js +46 -250
  64. package/dist/src/llm/ollama.js.map +1 -1
  65. package/dist/src/llm/openai.d.ts +1 -0
  66. package/dist/src/llm/openai.d.ts.map +1 -1
  67. package/dist/src/llm/openai.js +21 -7
  68. package/dist/src/llm/openai.js.map +1 -1
  69. package/dist/src/llm/repair/retry-policy.d.ts +48 -0
  70. package/dist/src/llm/repair/retry-policy.d.ts.map +1 -0
  71. package/dist/src/llm/repair/retry-policy.js +85 -0
  72. package/dist/src/llm/repair/retry-policy.js.map +1 -0
  73. package/dist/src/llm/repair/tool-repair.d.ts +39 -0
  74. package/dist/src/llm/repair/tool-repair.d.ts.map +1 -0
  75. package/dist/src/llm/repair/tool-repair.js +313 -0
  76. package/dist/src/llm/repair/tool-repair.js.map +1 -0
  77. package/dist/src/llm/shared/text-cleanup.d.ts +16 -0
  78. package/dist/src/llm/shared/text-cleanup.d.ts.map +1 -0
  79. package/dist/src/llm/shared/text-cleanup.js +120 -0
  80. package/dist/src/llm/shared/text-cleanup.js.map +1 -0
  81. package/dist/src/llm/shared/tool-parsing.d.ts +70 -0
  82. package/dist/src/llm/shared/tool-parsing.d.ts.map +1 -0
  83. package/dist/src/llm/shared/tool-parsing.js +355 -0
  84. package/dist/src/llm/shared/tool-parsing.js.map +1 -0
  85. package/dist/src/llm/validation/tool-call-schema.d.ts +83 -0
  86. package/dist/src/llm/validation/tool-call-schema.d.ts.map +1 -0
  87. package/dist/src/llm/validation/tool-call-schema.js +145 -0
  88. package/dist/src/llm/validation/tool-call-schema.js.map +1 -0
  89. package/dist/src/tools/built-in/bash.d.ts +5 -1
  90. package/dist/src/tools/built-in/bash.d.ts.map +1 -1
  91. package/dist/src/tools/built-in/bash.js +34 -46
  92. package/dist/src/tools/built-in/bash.js.map +1 -1
  93. package/dist/src/tools/built-in/index.d.ts +2 -1
  94. package/dist/src/tools/built-in/index.d.ts.map +1 -1
  95. package/dist/src/tools/built-in/index.js +3 -1
  96. package/dist/src/tools/built-in/index.js.map +1 -1
  97. package/dist/src/tools/built-in/pdf-report.d.ts +39 -0
  98. package/dist/src/tools/built-in/pdf-report.d.ts.map +1 -0
  99. package/dist/src/tools/built-in/pdf-report.js +326 -0
  100. package/dist/src/tools/built-in/pdf-report.js.map +1 -0
  101. package/dist/src/tools/executor.d.ts +7 -1
  102. package/dist/src/tools/executor.d.ts.map +1 -1
  103. package/dist/src/tools/executor.js +20 -5
  104. package/dist/src/tools/executor.js.map +1 -1
  105. package/dist/src/tools/shell/shell-executor.d.ts +71 -0
  106. package/dist/src/tools/shell/shell-executor.d.ts.map +1 -0
  107. package/dist/src/tools/shell/shell-executor.js +238 -0
  108. package/dist/src/tools/shell/shell-executor.js.map +1 -0
  109. package/package.json +9 -4
package/dist/bin/cmdr.js CHANGED
@@ -7,43 +7,133 @@
7
7
  */
8
8
  import { parseArgs, printHelp } from '../src/cli/args.js';
9
9
  import { startRepl } from '../src/cli/repl.js';
10
- import { GREEN, PURPLE, DIM, renderError, WHITE, CYAN } from '../src/cli/theme.js';
10
+ import { GREEN, PURPLE, DIM, renderError, CYAN } from '../src/cli/theme.js';
11
11
  import { OllamaAdapter } from '../src/llm/ollama.js';
12
12
  import { checkForUpdate } from '../src/cli/update-checker.js';
13
13
  import * as readline from 'readline';
14
+ import chalk from 'chalk';
14
15
  import { createRequire } from 'module';
15
16
  const require = createRequire(import.meta.url);
16
- const { version: VERSION } = require('../package.json');
17
+ const { version: VERSION } = require('../../package.json');
18
+ function isRecommendedModel(modelName) {
19
+ const name = modelName.toLowerCase();
20
+ return name.includes('coder') || name.includes('code') || name.includes('deepseek');
21
+ }
22
+ function defaultModelIndex(models) {
23
+ const recommended = models.findIndex(isRecommendedModel);
24
+ return recommended >= 0 ? recommended : 0;
25
+ }
17
26
  /** Prompt user to pick a model from the list. */
18
27
  function promptModelSelection(models) {
28
+ const fallbackIndex = defaultModelIndex(models);
29
+ if (!process.stdin.isTTY ||
30
+ !process.stdout.isTTY ||
31
+ typeof process.stdin.setRawMode !== 'function') {
32
+ console.log(` ${DIM('Non-interactive terminal detected, using:')} ${GREEN(models[fallbackIndex])}`);
33
+ return Promise.resolve(models[fallbackIndex]);
34
+ }
19
35
  return new Promise((resolve) => {
20
- console.log('');
21
- console.log(` ${PURPLE.bold('Available models')}`);
22
- console.log('');
23
- for (let i = 0; i < models.length; i++) {
24
- const label = models[i].toLowerCase().includes('coder')
25
- ? `${WHITE(models[i])} ${DIM('(recommended)')}`
26
- : WHITE(models[i]);
27
- console.log(` ${GREEN(`${i + 1}.`)} ${label}`);
28
- }
29
- console.log('');
30
- const rl = readline.createInterface({
31
- input: process.stdin,
32
- output: process.stdout,
33
- terminal: true,
34
- });
35
- rl.question(` ${CYAN('Select model')} ${DIM(`[1-${models.length}]`)}: `, (answer) => {
36
- rl.close();
37
- const idx = parseInt(answer.trim(), 10) - 1;
38
- if (idx >= 0 && idx < models.length) {
39
- resolve(models[idx]);
36
+ const stdin = process.stdin;
37
+ const stdout = process.stdout;
38
+ const wasRaw = Boolean(stdin.isRaw);
39
+ let selected = fallbackIndex;
40
+ let renderedLines = 0;
41
+ const clearRendered = () => {
42
+ if (renderedLines <= 0)
43
+ return;
44
+ readline.moveCursor(stdout, 0, -renderedLines);
45
+ readline.clearScreenDown(stdout);
46
+ renderedLines = 0;
47
+ };
48
+ const renderMenu = () => {
49
+ clearRendered();
50
+ const menuWidth = process.stdout.columns || 80;
51
+ const maxModelWidth = Math.max(14, menuWidth - 24);
52
+ const compact = (value) => {
53
+ if (value.length <= maxModelWidth)
54
+ return value;
55
+ return `${value.slice(0, Math.max(1, maxModelWidth - 3))}...`;
56
+ };
57
+ const lines = [
58
+ '',
59
+ ` ${PURPLE.bold('Model Matrix')}`,
60
+ ` ${DIM('Use ↑/↓ to target, Enter to initialize')}`,
61
+ '',
62
+ ];
63
+ for (let i = 0; i < models.length; i++) {
64
+ const isActive = i === selected;
65
+ const isRecommended = isRecommendedModel(models[i]);
66
+ const pointer = isActive ? CYAN.bold('▶') : DIM('·');
67
+ const ordinal = DIM(`${String(i + 1).padStart(2, ' ')}.`);
68
+ const modelName = compact(models[i]);
69
+ const modelLabel = isActive
70
+ ? chalk.bgHex('#11303A').hex('#B7FFE3').bold(` ${modelName} `)
71
+ : DIM(modelName);
72
+ const recommendation = isRecommended
73
+ ? isActive
74
+ ? ` ${GREEN('●')} ${DIM('recommended')}`
75
+ : ` ${DIM('· recommended')}`
76
+ : '';
77
+ lines.push(` ${pointer} ${ordinal} ${modelLabel}${recommendation}`);
40
78
  }
41
- else {
42
- // Default to first model on invalid input
43
- console.log(` ${DIM('Invalid selection, using:')} ${GREEN(models[0])}`);
44
- resolve(models[0]);
79
+ lines.push('');
80
+ lines.push(` ${DIM('Esc picks default:')} ${GREEN(models[fallbackIndex])}`);
81
+ stdout.write(lines.join('\n'));
82
+ renderedLines = lines.length;
83
+ };
84
+ const cleanup = () => {
85
+ stdin.off('keypress', onKeypress);
86
+ if (typeof stdin.setRawMode === 'function') {
87
+ stdin.setRawMode(wasRaw);
45
88
  }
46
- });
89
+ stdin.pause();
90
+ stdout.write('\x1B[?25h');
91
+ };
92
+ const finish = (chosenModel, statusLine) => {
93
+ cleanup();
94
+ clearRendered();
95
+ console.log(statusLine);
96
+ resolve(chosenModel);
97
+ };
98
+ const onKeypress = (input, key) => {
99
+ if (key.ctrl && key.name === 'c') {
100
+ cleanup();
101
+ clearRendered();
102
+ stdout.write('\n');
103
+ process.exit(130);
104
+ }
105
+ if (key.name === 'up') {
106
+ selected = (selected - 1 + models.length) % models.length;
107
+ renderMenu();
108
+ return;
109
+ }
110
+ if (key.name === 'down') {
111
+ selected = (selected + 1) % models.length;
112
+ renderMenu();
113
+ return;
114
+ }
115
+ if (key.name === 'return') {
116
+ finish(models[selected], ` ${DIM('Selected model:')} ${GREEN(models[selected])}`);
117
+ return;
118
+ }
119
+ if (key.name === 'escape') {
120
+ finish(models[fallbackIndex], ` ${DIM('Using default model:')} ${GREEN(models[fallbackIndex])}`);
121
+ return;
122
+ }
123
+ if (input && /^\d$/.test(input)) {
124
+ const idx = parseInt(input, 10) - 1;
125
+ if (idx >= 0 && idx < models.length) {
126
+ selected = idx;
127
+ renderMenu();
128
+ }
129
+ }
130
+ };
131
+ readline.emitKeypressEvents(stdin);
132
+ stdin.setRawMode?.(true);
133
+ stdin.resume();
134
+ stdout.write('\x1B[?25l');
135
+ stdin.on('keypress', onKeypress);
136
+ renderMenu();
47
137
  });
48
138
  }
49
139
  async function main() {
@@ -1 +1 @@
1
- {"version":3,"file":"cmdr.js","sourceRoot":"","sources":["../../bin/cmdr.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cmdr.js","sourceRoot":"","sources":["../../bin/cmdr.ts"],"names":[],"mappings":"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"}
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cmdr-agent",
3
- "version": "2.4.0",
3
+ "version": "2.5.1",
4
4
  "description": "Open-source multi-agent coding tool for your terminal. Powered by Ollama.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -34,18 +34,23 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "chalk": "^5.3.0",
37
- "ink": "^5.2.1",
37
+ "highlight.js": "^11.11.1",
38
+ "ink": "npm:@jrichman/ink@6.6.7",
39
+ "ink-spinner": "^5.0.0",
38
40
  "ink-text-input": "^6.0.0",
41
+ "lowlight": "^3.3.0",
39
42
  "marked": "^14.0.0",
40
43
  "marked-terminal": "^7.2.0",
41
44
  "ora": "^8.0.0",
42
- "react": "^18.3.1",
45
+ "react": "^19.2.0",
43
46
  "smol-toml": "^1.6.1",
47
+ "string-width": "^8.1.0",
48
+ "strip-ansi": "^7.1.0",
44
49
  "zod": "^3.23.0"
45
50
  },
46
51
  "devDependencies": {
47
52
  "@types/node": "^22.0.0",
48
- "@types/react": "^18.3.28",
53
+ "@types/react": "^19.2.2",
49
54
  "tsx": "^4.21.0",
50
55
  "typescript": "^5.6.0",
51
56
  "vitest": "^2.1.0"
@@ -2,8 +2,8 @@
2
2
  * Ink-based REPL application — replaces raw readline.
3
3
  *
4
4
  * Architecture:
5
- * - <Static> renders all past output (scrollback, never re-rendered)
6
- * - Dynamic section: active spinner OR input prompt
5
+ * - Windowed transcript viewport for bounded scrollback rendering
6
+ * - Dynamic section: active spinner, approval prompts, and input composer
7
7
  * - State machine: idle | processing | waiting_approval | exiting
8
8
  */
9
9
  import React from 'react';
@@ -1 +1 @@
1
- {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink/App.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAA;AAGvE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAClE,OAAO,KAAK,EAAE,UAAU,EAAkE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACjI,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAI9D,OAAO,EACsD,cAAc,EAC1E,MAAM,sCAAsC,CAAA;AAE7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAA;AAoEvE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,KAAK,CAAA;IACZ,OAAO,EAAE,cAAc,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,OAAO,EAAE,UAAU,CAAA;IACnB,YAAY,EAAE,YAAY,CAAA;IAC1B,gBAAgB,CAAC,EAAE,UAAU,CAAA;IAC7B,WAAW,EAAE,WAAW,CAAA;IACxB,WAAW,EAAE,WAAW,CAAA;IACxB,aAAa,EAAE,aAAa,CAAA;IAC5B,SAAS,EAAE,SAAS,CAAA;IACpB,YAAY,EAAE,YAAY,CAAA;IAC1B,aAAa,EAAE,aAAa,CAAA;IAC5B,aAAa,EAAE,aAAa,CAAA;IAC5B,aAAa,EAAE,aAAa,CAAA;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3B,SAAS,EAAE,cAAc,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAoED,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,KAAK,EAAE,WAAW,GAAG,KAAK,CAAC,YAAY,CAm/BlE"}
1
+ {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink/App.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAA4D,MAAM,OAAO,CAAA;AAGhF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAClE,OAAO,KAAK,EAAE,UAAU,EAAkE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACjI,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAI9D,OAAO,EACsD,cAAc,EAC1E,MAAM,sCAAsC,CAAA;AAE7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAA;AAqEvE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,KAAK,CAAA;IACZ,OAAO,EAAE,cAAc,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,OAAO,EAAE,UAAU,CAAA;IACnB,YAAY,EAAE,YAAY,CAAA;IAC1B,gBAAgB,CAAC,EAAE,UAAU,CAAA;IAC7B,WAAW,EAAE,WAAW,CAAA;IACxB,WAAW,EAAE,WAAW,CAAA;IACxB,aAAa,EAAE,aAAa,CAAA;IAC5B,SAAS,EAAE,SAAS,CAAA;IACpB,YAAY,EAAE,YAAY,CAAA;IAC1B,aAAa,EAAE,aAAa,CAAA;IAC5B,aAAa,EAAE,aAAa,CAAA;IAC5B,aAAa,EAAE,aAAa,CAAA;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3B,SAAS,EAAE,cAAc,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAoED,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,KAAK,EAAE,WAAW,GAAG,KAAK,CAAC,YAAY,CAyjClE"}
@@ -3,12 +3,12 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  * Ink-based REPL application — replaces raw readline.
4
4
  *
5
5
  * Architecture:
6
- * - <Static> renders all past output (scrollback, never re-rendered)
7
- * - Dynamic section: active spinner OR input prompt
6
+ * - Windowed transcript viewport for bounded scrollback rendering
7
+ * - Dynamic section: active spinner, approval prompts, and input composer
8
8
  * - State machine: idle | processing | waiting_approval | exiting
9
9
  */
10
- import { useState, useCallback, useEffect, useRef } from 'react';
11
- import { Box, Text, Static, useApp, useInput } from 'ink';
10
+ import { useState, useCallback, useEffect, useMemo, useRef } from 'react';
11
+ import { Box, Text, useApp, useInput } from 'ink';
12
12
  import TextInput from 'ink-text-input';
13
13
  import { getDefaultContextLength } from '../../llm/model-registry.js';
14
14
  import { isSlashCommand, parseSlashCommand, getCommand } from '../commands.js';
@@ -16,20 +16,11 @@ import { saveSession, loadSession, } from '../../session/session-persistence.js'
16
16
  import { getTeamPreset } from '../../core/presets.js';
17
17
  import { listAvailableServers, getServerDefinition, toMcpConfig, getMissingEnvVars } from '../../config/mcp-registry.js';
18
18
  import StatusBar from './StatusBar.js';
19
- // We use chalk directly for coloring since Ink <Text> color props are limited
20
- import chalk from 'chalk';
21
- const GREEN = chalk.hex('#00FF41');
22
- const GREEN_DIM = chalk.hex('#00BB30');
23
- const PURPLE = chalk.hex('#BF40FF');
24
- const CYAN = chalk.hex('#00FFFF');
25
- const DIM = chalk.hex('#555555');
26
- const WHITE = chalk.hex('#E0E0E0');
27
- const YELLOW = chalk.hex('#FFD700');
28
- const RED = chalk.hex('#FF3333');
19
+ import PromptInput from './PromptInput.js';
20
+ import { StreamingMarkdownRenderer } from '../renderer.js';
21
+ import { GREEN, PURPLE, CYAN, DIM, WHITE, YELLOW, RED, SEPARATOR, } from '../theme.js';
29
22
  const SUCCESS_SYM = GREEN('✓');
30
23
  const ERROR_SYM = RED('✗');
31
- const TOOL_SYM = CYAN('⚡');
32
- const SEPARATOR = GREEN_DIM('─'.repeat(60));
33
24
  // ---------------------------------------------------------------------------
34
25
  // Verb pool for spinner
35
26
  // ---------------------------------------------------------------------------
@@ -57,6 +48,7 @@ function toPastTense(verb) {
57
48
  }
58
49
  return stem + 'ed';
59
50
  }
51
+ const MAX_OUTPUT_LINES = 6000;
60
52
  // ---------------------------------------------------------------------------
61
53
  // Tool result summary
62
54
  // ---------------------------------------------------------------------------
@@ -116,8 +108,8 @@ export default function App(props) {
116
108
  const { agent, session, permissionManager, adapter, orchestrator, costTracker, undoManager, pluginManager, mcpClient, toolRegistry, agentRegistry, commandLoader, taskScheduler, ollamaUrl, verbose, doSave, autoSaver, } = props;
117
109
  const { exit } = useApp();
118
110
  const [state, setState] = useState('idle');
119
- const [inputValue, setInputValue] = useState('');
120
111
  const [outputLines, setOutputLines] = useState([]);
112
+ const [historyScrollOffset, setHistoryScrollOffset] = useState(0);
121
113
  const [spinnerText, setSpinnerText] = useState('');
122
114
  const [approval, setApproval] = useState(null);
123
115
  const [approvalInput, setApprovalInput] = useState('');
@@ -137,42 +129,73 @@ export default function App(props) {
137
129
  }, [state]);
138
130
  // Append output to scrollback
139
131
  const appendOutput = useCallback((text) => {
140
- setOutputLines(prev => [...prev, { id: nextId(), text }]);
132
+ setHistoryScrollOffset(0);
133
+ setOutputLines(prev => {
134
+ const next = [...prev, { id: nextId(), text }];
135
+ return next.length > MAX_OUTPUT_LINES ? next.slice(next.length - MAX_OUTPUT_LINES) : next;
136
+ });
141
137
  }, []);
142
138
  // Append multiple lines at once
143
139
  const appendLines = useCallback((lines) => {
144
- setOutputLines(prev => [
145
- ...prev,
146
- ...lines.map(text => ({ id: nextId(), text })),
147
- ]);
140
+ if (lines.length === 0)
141
+ return;
142
+ setHistoryScrollOffset(0);
143
+ setOutputLines(prev => {
144
+ const next = [
145
+ ...prev,
146
+ ...lines.map(text => ({ id: nextId(), text })),
147
+ ];
148
+ return next.length > MAX_OUTPUT_LINES ? next.slice(next.length - MAX_OUTPUT_LINES) : next;
149
+ });
148
150
  }, []);
151
+ const appendRenderedMarkdown = useCallback((rendered) => {
152
+ if (!rendered)
153
+ return;
154
+ const prefixed = rendered
155
+ .split('\n')
156
+ .map((line) => ` ${PURPLE('│')} ${line}`);
157
+ appendLines(prefixed);
158
+ }, [appendLines]);
159
+ const terminalRows = process.stdout.rows || 42;
160
+ const reservedRows = state === 'idle' ? 9 : state === 'waiting_approval' ? 13 : 6;
161
+ const historyWindowSize = Math.max(8, terminalRows - reservedRows);
162
+ const visibleOutputLines = useMemo(() => {
163
+ const end = Math.max(0, outputLines.length - historyScrollOffset);
164
+ const start = Math.max(0, end - historyWindowSize);
165
+ return outputLines.slice(start, end);
166
+ }, [outputLines, historyScrollOffset, historyWindowSize]);
149
167
  // ---------------------------------------------------------------------------
150
168
  // Spinner management
151
169
  // ---------------------------------------------------------------------------
152
170
  const spinnerRef = useRef(null);
153
171
  const verbRef = useRef(pickVerb());
154
172
  const spinnerStartRef = useRef(0);
173
+ const turnStartRef = useRef(0);
174
+ const lastVerbRotateSecondRef = useRef(0);
155
175
  const spinnerFrameRef = useRef(0);
156
176
  const SPINNER_FRAMES = ['◇ ', '◈ ', '◆ ', '◈ '];
157
177
  const startSpinner = useCallback((mode, toolName) => {
158
178
  stopSpinnerFn();
159
179
  spinnerStartRef.current = Date.now();
160
180
  verbRef.current = pickVerb();
181
+ lastVerbRotateSecondRef.current = 0;
161
182
  spinnerFrameRef.current = 0;
183
+ if (mode === 'tool') {
184
+ setSpinnerText(` ${CYAN('⚡')} ${CYAN(toolName ?? 'tool')} ${DIM('executing...')}`);
185
+ return;
186
+ }
162
187
  const update = () => {
163
188
  spinnerFrameRef.current = (spinnerFrameRef.current + 1) % SPINNER_FRAMES.length;
164
189
  const frame = SPINNER_FRAMES[spinnerFrameRef.current];
165
190
  const elapsed = Math.round((Date.now() - spinnerStartRef.current) / 1000);
166
- if (mode === 'thinking') {
167
- // Rotate verb every ~3s
168
- if (elapsed > 0 && elapsed % 3 === 0) {
169
- verbRef.current = pickVerb();
170
- }
171
- setSpinnerText(` ${PURPLE(frame)}${PURPLE(verbRef.current + '...')} ${DIM(`(${elapsed}s)`)}`);
172
- }
173
- else {
174
- setSpinnerText(` ${CYAN('⚡')} ${CYAN(toolName ?? 'tool')} ${DIM('executing...')}`);
191
+ // Rotate verb every ~3s, once per threshold crossing.
192
+ if (elapsed > 0 &&
193
+ elapsed % 3 === 0 &&
194
+ elapsed !== lastVerbRotateSecondRef.current) {
195
+ verbRef.current = pickVerb();
196
+ lastVerbRotateSecondRef.current = elapsed;
175
197
  }
198
+ setSpinnerText(` ${PURPLE(frame)}${PURPLE(verbRef.current + '...')} ${DIM(`(${elapsed}s)`)}`);
176
199
  };
177
200
  update();
178
201
  spinnerRef.current = setInterval(update, 120);
@@ -185,7 +208,8 @@ export default function App(props) {
185
208
  setSpinnerText('');
186
209
  }, []);
187
210
  const getCompletionSummary = useCallback(() => {
188
- const elapsed = Math.round((Date.now() - spinnerStartRef.current) / 1000);
211
+ const start = turnStartRef.current || spinnerStartRef.current;
212
+ const elapsed = Math.round((Date.now() - start) / 1000);
189
213
  return `${toPastTense(verbRef.current)} for ${elapsed}s`;
190
214
  }, []);
191
215
  // ---------------------------------------------------------------------------
@@ -228,10 +252,14 @@ export default function App(props) {
228
252
  // Handle user message (streaming)
229
253
  // ---------------------------------------------------------------------------
230
254
  const handleUserMessage = useCallback(async (message) => {
255
+ turnStartRef.current = Date.now();
231
256
  appendOutput('');
232
257
  startSpinner('thinking');
233
- let fullOutput = '';
258
+ const streamRenderer = new StreamingMarkdownRenderer({
259
+ width: Math.max(60, (process.stdout.columns || 96) - 8),
260
+ });
234
261
  let firstText = true;
262
+ let hadTextOutput = false;
235
263
  let currentTool = '';
236
264
  let currentToolInput = {};
237
265
  let toolCallCount = 0;
@@ -275,27 +303,22 @@ export default function App(props) {
275
303
  firstText = false;
276
304
  }
277
305
  const chunk = event.data;
278
- fullOutput += chunk;
279
- // Stream text by appending to the last output line
280
- // We'll accumulate and print at the end for cleaner output
306
+ const rendered = streamRenderer.push(chunk);
307
+ if (rendered) {
308
+ hadTextOutput = true;
309
+ appendRenderedMarkdown(rendered);
310
+ }
281
311
  break;
282
312
  }
283
313
  case 'tool_use': {
284
314
  stopSpinnerFn();
285
- if (!firstText) {
286
- // Flush accumulated text — strip raw tool_call/thought blocks
287
- if (fullOutput) {
288
- let displayText = fullOutput;
289
- displayText = displayText.replace(/```tool_call[\s\S]*?```/g, '').trim();
290
- displayText = displayText.replace(/```thought[\s\S]*?```/g, '').trim();
291
- if (displayText) {
292
- const formatted = displayText.split('\n').map(l => ` ${PURPLE('│')} ${l}`).join('\n');
293
- appendOutput(formatted);
294
- }
295
- fullOutput = '';
296
- }
297
- firstText = true;
315
+ const rendered = streamRenderer.flush();
316
+ if (rendered) {
317
+ hadTextOutput = true;
318
+ appendRenderedMarkdown(rendered);
319
+ appendOutput('');
298
320
  }
321
+ firstText = true;
299
322
  const block = event.data;
300
323
  currentTool = block.name;
301
324
  currentToolInput = block.input;
@@ -337,6 +360,11 @@ export default function App(props) {
337
360
  break;
338
361
  }
339
362
  case 'done': {
363
+ const rendered = streamRenderer.flush();
364
+ if (rendered) {
365
+ hadTextOutput = true;
366
+ appendRenderedMarkdown(rendered);
367
+ }
340
368
  stopSpinnerFn();
341
369
  break;
342
370
  }
@@ -364,8 +392,9 @@ export default function App(props) {
364
392
  // Retry once with compacted context
365
393
  try {
366
394
  startSpinner('thinking');
367
- fullOutput = '';
395
+ streamRenderer.reset();
368
396
  firstText = true;
397
+ hadTextOutput = false;
369
398
  for await (const event of agent.stream('', callbacks, abortController.signal)) {
370
399
  switch (event.type) {
371
400
  case 'text': {
@@ -373,11 +402,21 @@ export default function App(props) {
373
402
  stopSpinnerFn();
374
403
  firstText = false;
375
404
  }
376
- fullOutput += event.data;
405
+ const rendered = streamRenderer.push(event.data);
406
+ if (rendered) {
407
+ hadTextOutput = true;
408
+ appendRenderedMarkdown(rendered);
409
+ }
377
410
  break;
378
411
  }
379
412
  case 'tool_use': {
380
413
  stopSpinnerFn();
414
+ const rendered = streamRenderer.flush();
415
+ if (rendered) {
416
+ hadTextOutput = true;
417
+ appendRenderedMarkdown(rendered);
418
+ appendOutput('');
419
+ }
381
420
  const block = event.data;
382
421
  currentTool = block.name;
383
422
  currentToolInput = block.input;
@@ -412,6 +451,11 @@ export default function App(props) {
412
451
  }
413
452
  }
414
453
  }
454
+ const retryRemainder = streamRenderer.flush();
455
+ if (retryRemainder) {
456
+ hadTextOutput = true;
457
+ appendRenderedMarkdown(retryRemainder);
458
+ }
415
459
  }
416
460
  catch (retryErr) {
417
461
  stopSpinnerFn();
@@ -426,17 +470,12 @@ export default function App(props) {
426
470
  appendOutput(`\n ${ERROR_SYM} ${RED.bold(msg)}\n`);
427
471
  }
428
472
  }
429
- // Flush remaining text — strip raw tool_call/thought blocks from display
430
- if (fullOutput) {
431
- let displayText = fullOutput;
432
- displayText = displayText.replace(/```tool_call[\s\S]*?```/g, '').trim();
433
- displayText = displayText.replace(/```thought[\s\S]*?```/g, '').trim();
434
- if (displayText) {
435
- const formatted = displayText.split('\n').map(l => ` ${PURPLE('│')} ${l}`).join('\n');
436
- appendOutput(formatted);
437
- }
473
+ const remainder = streamRenderer.flush();
474
+ if (remainder) {
475
+ hadTextOutput = true;
476
+ appendRenderedMarkdown(remainder);
438
477
  }
439
- if (fullOutput || !firstText) {
478
+ if (hadTextOutput || !firstText) {
440
479
  appendOutput('');
441
480
  }
442
481
  // Turn summary
@@ -467,11 +506,12 @@ export default function App(props) {
467
506
  appendOutput(SEPARATOR);
468
507
  appendOutput('');
469
508
  }, [agent, session, adapter, costTracker, undoManager, verbose, autoSaver, doSave,
470
- appendOutput, startSpinner, stopSpinnerFn, getCompletionSummary]);
509
+ appendOutput, appendRenderedMarkdown, startSpinner, stopSpinnerFn, getCompletionSummary]);
471
510
  // ---------------------------------------------------------------------------
472
511
  // Handle team message
473
512
  // ---------------------------------------------------------------------------
474
513
  const handleTeamMessage = useCallback(async (goal, teamConfig) => {
514
+ turnStartRef.current = Date.now();
475
515
  appendOutput('');
476
516
  appendOutput(` ${PURPLE('◈')} Running team ${PURPLE.bold(teamConfig.name)} with ${teamConfig.agents.length} agents...`);
477
517
  appendOutput('');
@@ -872,7 +912,6 @@ export default function App(props) {
872
912
  // ---------------------------------------------------------------------------
873
913
  const handleSubmit = useCallback(async (value) => {
874
914
  const input = value.trim();
875
- setInputValue('');
876
915
  if (!input)
877
916
  return;
878
917
  if (stateRef.current !== 'idle')
@@ -946,6 +985,20 @@ export default function App(props) {
946
985
  // Keyboard input handling (Ctrl+C, Ctrl+D)
947
986
  // ---------------------------------------------------------------------------
948
987
  useInput((input, key) => {
988
+ const maxScrollOffset = Math.max(0, outputLines.length - historyWindowSize);
989
+ const pageStep = Math.max(1, Math.floor(historyWindowSize * 0.7));
990
+ if (key.pageUp) {
991
+ setHistoryScrollOffset((prev) => Math.min(maxScrollOffset, prev + pageStep));
992
+ return;
993
+ }
994
+ if (key.pageDown) {
995
+ setHistoryScrollOffset((prev) => Math.max(0, prev - pageStep));
996
+ return;
997
+ }
998
+ if (key.escape && historyScrollOffset > 0) {
999
+ setHistoryScrollOffset(0);
1000
+ return;
1001
+ }
949
1002
  // Ctrl+C handling
950
1003
  if (key.ctrl && input === 'c') {
951
1004
  const now = Date.now();
@@ -1015,11 +1068,11 @@ export default function App(props) {
1015
1068
  // ---------------------------------------------------------------------------
1016
1069
  // Render
1017
1070
  // ---------------------------------------------------------------------------
1018
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Static, { items: outputLines, children: (line) => (_jsx(Text, { children: line.text }, line.id)) }), state === 'processing' && spinnerText && (_jsx(Text, { children: spinnerText })), state === 'waiting_approval' && approval && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: '' }), _jsx(Text, { children: ` ${YELLOW('⚠')} ${WHITE('Tool approval required')} ${DIM('[')}${approval.riskLevel === 'dangerous' ? RED(approval.riskLevel.toUpperCase()) : YELLOW(approval.riskLevel.toUpperCase())}${DIM(']')}` }), _jsx(Text, { children: ` ${DIM('Tool:')} ${CYAN(approval.toolName)}` }), Object.entries(approval.input).map(([key, val]) => {
1071
+ return (_jsxs(Box, { flexDirection: "column", height: terminalRows, children: [_jsx(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: visibleOutputLines.map((line) => (_jsx(Text, { children: line.text }, line.id))) }), historyScrollOffset > 0 && (_jsx(Text, { children: ` ${DIM('Scrollback')} ${WHITE(String(historyScrollOffset))} ${DIM('(PgUp/PgDn, Esc to jump to live)')}` })), state === 'processing' && spinnerText && (_jsx(Text, { children: spinnerText })), state === 'waiting_approval' && approval && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: '' }), _jsx(Text, { children: ` ${YELLOW('⚠')} ${WHITE('Tool approval required')} ${DIM('[')}${approval.riskLevel === 'dangerous' ? RED(approval.riskLevel.toUpperCase()) : YELLOW(approval.riskLevel.toUpperCase())}${DIM(']')}` }), _jsx(Text, { children: ` ${DIM('Tool:')} ${CYAN(approval.toolName)}` }), Object.entries(approval.input).map(([key, val]) => {
1019
1072
  const display = typeof val === 'string'
1020
1073
  ? val.length > 120 ? val.slice(0, 120) + DIM('...') : val
1021
1074
  : JSON.stringify(val).slice(0, 120);
1022
1075
  return _jsx(Text, { children: ` ${DIM(key + ':')} ${WHITE(display)}` }, key);
1023
- }), _jsx(Text, { children: '' }), _jsx(Text, { children: ` ${GREEN('y')}${DIM('es')} ${DIM('/')} ${RED('n')}${DIM('o')} ${DIM('/')} ${PURPLE('a')}${DIM('lways allow this tool')}` }), _jsxs(Box, { children: [_jsx(Text, { children: ` ${YELLOW('?')} ` }), _jsx(TextInput, { value: approvalInput, onChange: setApprovalInput, onSubmit: handleApprovalSubmit })] })] })), state === 'idle' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(StatusBar, { model: currentModelRef.current, tokensIn: tokensIn, tokensOut: tokensOut, turns: turnCount, agentCount: agentRegistry.list().length, permissionMode: permissionManager.getMode(), cwd: process.cwd(), gitBranch: props.gitBranch, contextPct: session.maxContextTokens ? Math.round((session.tokenCount / session.maxContextTokens) * 100) : 0, version: props.version }), _jsxs(Box, { children: [_jsxs(Text, { children: [GREEN.bold(''), " "] }), _jsx(TextInput, { value: inputValue, onChange: setInputValue, onSubmit: handleSubmit, placeholder: "Ask anything, @file to include, /help for commands" })] })] }))] }));
1076
+ }), _jsx(Text, { children: '' }), _jsx(Text, { children: ` ${GREEN('y')}${DIM('es')} ${DIM('/')} ${RED('n')}${DIM('o')} ${DIM('/')} ${PURPLE('a')}${DIM('lways allow this tool')}` }), _jsxs(Box, { children: [_jsx(Text, { children: ` ${YELLOW('?')} ` }), _jsx(TextInput, { value: approvalInput, onChange: setApprovalInput, onSubmit: handleApprovalSubmit })] })] })), _jsx(StatusBar, { model: currentModelRef.current, tokensIn: tokensIn, tokensOut: tokensOut, turns: turnCount, agentCount: agentRegistry.list().length, permissionMode: permissionManager.getMode(), cwd: process.cwd(), gitBranch: props.gitBranch, contextPct: session.maxContextTokens ? Math.round((session.tokenCount / session.maxContextTokens) * 100) : 0, version: props.version }), state === 'idle' && (_jsx(PromptInput, { onSubmit: handleSubmit, placeholder: "Ask anything, @file to include, /help for commands" }))] }));
1024
1077
  }
1025
1078
  //# sourceMappingURL=App.js.map