@iaforged/context-code 1.1.7 → 1.2.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 (95) hide show
  1. package/README.md +56 -0
  2. package/dist/src/commands/agent/agent.js +62 -0
  3. package/dist/src/commands/agent/index.js +1 -1
  4. package/dist/src/commands/model/model.js +9 -5
  5. package/dist/src/commands/orchestrate/index.js +2 -2
  6. package/dist/src/commands/orchestrate/orchestrate.js +12 -627
  7. package/dist/src/commands/tasks/index.js +1 -1
  8. package/dist/src/commands/tasks/tasks.js +8 -3
  9. package/dist/src/commands/team/index.js +2 -2
  10. package/dist/src/commands/team/team.js +12 -589
  11. package/dist/src/commands/timeline/index.js +8 -0
  12. package/dist/src/commands/timeline/timeline.js +194 -0
  13. package/dist/src/commands/workspace/workspace.js +3 -3
  14. package/dist/src/commands.js +2 -6
  15. package/dist/src/components/AgentActivitySidebar.js +50 -0
  16. package/dist/src/components/AgentProgressLine.js +5 -5
  17. package/dist/src/components/ModelPicker.js +252 -441
  18. package/dist/src/components/PromptInput/Notifications.js +1 -1
  19. package/dist/src/components/PromptInput/PromptInput.js +7 -3
  20. package/dist/src/components/PromptInput/PromptInputFooter.js +10 -29
  21. package/dist/src/components/Spinner/TeammateSpinnerLine.js +20 -62
  22. package/dist/src/components/Spinner/TeammateSpinnerTree.js +16 -258
  23. package/dist/src/components/Spinner/teammateSelectHint.js +1 -1
  24. package/dist/src/components/Spinner/utils.js +3 -6
  25. package/dist/src/components/ThemeBrowser.js +120 -0
  26. package/dist/src/components/ThemePicker.js +113 -321
  27. package/dist/src/components/design-system/ThemeProvider.js +3 -0
  28. package/dist/src/components/mcp/MCPListPanel.js +138 -444
  29. package/dist/src/components/permissions/SandboxPermissionRequest.js +5 -5
  30. package/dist/src/components/teams/TeamStatus.js +7 -71
  31. package/dist/src/constants/spinnerVerbs.js +80 -180
  32. package/dist/src/context/modalStackContext.js +12 -0
  33. package/dist/src/hooks/useTextInput.js +28 -18
  34. package/dist/src/main.js +12 -0
  35. package/dist/src/screens/REPL.js +386 -320
  36. package/dist/src/services/api/errors.js +1 -1
  37. package/dist/src/services/api/openai.js +70 -22
  38. package/dist/src/services/api/withRetry.js +3 -2
  39. package/dist/src/skills/loadSkillsDir.js +1 -0
  40. package/dist/src/tools/AgentTool/UI.js +8 -8
  41. package/dist/src/tools/AgentTool/loadAgentsDir.js +9 -4
  42. package/dist/src/tools/AgentTool/providerAgents.js +71 -0
  43. package/dist/src/tools/BashTool/bashSecurity.js +1 -1
  44. package/dist/src/utils/handlePromptSubmit.js +12 -2
  45. package/dist/src/utils/processUserInput/processSlashCommand.js +9 -5
  46. package/dist/src/utils/sembleMcp/common.js +5 -0
  47. package/dist/src/utils/sembleMcp/setup.js +119 -0
  48. package/dist/src/utils/theme.js +24 -3
  49. package/dist/src/utils/themes/bootstrap.js +109 -0
  50. package/dist/src/utils/themes/builtin/opencode/_index.json +41 -0
  51. package/dist/src/utils/themes/builtin/opencode/amoled.json +49 -0
  52. package/dist/src/utils/themes/builtin/opencode/aura.json +51 -0
  53. package/dist/src/utils/themes/builtin/opencode/ayu.json +51 -0
  54. package/dist/src/utils/themes/builtin/opencode/carbonfox.json +53 -0
  55. package/dist/src/utils/themes/builtin/opencode/catppuccin-frappe.json +85 -0
  56. package/dist/src/utils/themes/builtin/opencode/catppuccin-macchiato.json +85 -0
  57. package/dist/src/utils/themes/builtin/opencode/catppuccin.json +45 -0
  58. package/dist/src/utils/themes/builtin/opencode/cobalt2.json +87 -0
  59. package/dist/src/utils/themes/builtin/opencode/cursor.json +91 -0
  60. package/dist/src/utils/themes/builtin/opencode/dracula.json +49 -0
  61. package/dist/src/utils/themes/builtin/opencode/everforest.json +89 -0
  62. package/dist/src/utils/themes/builtin/opencode/flexoki.json +86 -0
  63. package/dist/src/utils/themes/builtin/opencode/github.json +85 -0
  64. package/dist/src/utils/themes/builtin/opencode/gruvbox.json +45 -0
  65. package/dist/src/utils/themes/builtin/opencode/kanagawa.json +89 -0
  66. package/dist/src/utils/themes/builtin/opencode/lucent-orng.json +87 -0
  67. package/dist/src/utils/themes/builtin/opencode/material.json +87 -0
  68. package/dist/src/utils/themes/builtin/opencode/matrix.json +91 -0
  69. package/dist/src/utils/themes/builtin/opencode/mercury.json +86 -0
  70. package/dist/src/utils/themes/builtin/opencode/monokai.json +49 -0
  71. package/dist/src/utils/themes/builtin/opencode/nightowl.json +46 -0
  72. package/dist/src/utils/themes/builtin/opencode/nord.json +46 -0
  73. package/dist/src/utils/themes/builtin/opencode/oc-2.json +88 -0
  74. package/dist/src/utils/themes/builtin/opencode/one-dark.json +89 -0
  75. package/dist/src/utils/themes/builtin/opencode/onedarkpro.json +45 -0
  76. package/dist/src/utils/themes/builtin/opencode/opencode.json +89 -0
  77. package/dist/src/utils/themes/builtin/opencode/orng.json +87 -0
  78. package/dist/src/utils/themes/builtin/opencode/osaka-jade.json +88 -0
  79. package/dist/src/utils/themes/builtin/opencode/palenight.json +85 -0
  80. package/dist/src/utils/themes/builtin/opencode/rosepine.json +85 -0
  81. package/dist/src/utils/themes/builtin/opencode/shadesofpurple.json +51 -0
  82. package/dist/src/utils/themes/builtin/opencode/solarized.json +49 -0
  83. package/dist/src/utils/themes/builtin/opencode/synthwave84.json +87 -0
  84. package/dist/src/utils/themes/builtin/opencode/tokyonight.json +47 -0
  85. package/dist/src/utils/themes/builtin/opencode/vercel.json +90 -0
  86. package/dist/src/utils/themes/builtin/opencode/vesper.json +51 -0
  87. package/dist/src/utils/themes/builtin/opencode/zenburn.json +87 -0
  88. package/dist/src/utils/themes/index.js +4 -0
  89. package/dist/src/utils/themes/loader.js +147 -0
  90. package/dist/src/utils/themes/opencodeMapper.js +124 -0
  91. package/dist/src/utils/themes/resolver.js +66 -0
  92. package/dist/src/utils/themes/types.js +1 -0
  93. package/docs/MCP_SERVERS.md +27 -1
  94. package/docs/comandos.md +16 -4
  95. package/package.json +1 -1
@@ -56,7 +56,7 @@ export function SandboxPermissionRequest(t0) {
56
56
  let t4;
57
57
  if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
58
58
  t4 = {
59
- label: "Yes",
59
+ label: "Si",
60
60
  value: "yes"
61
61
  };
62
62
  $[3] = t4;
@@ -67,7 +67,7 @@ export function SandboxPermissionRequest(t0) {
67
67
  let t5;
68
68
  if ($[4] !== host) {
69
69
  t5 = !managedDomainsOnly ? [{
70
- label: _jsxs(Text, { children: ["Yes, and don't ask again for ", _jsx(Text, { bold: true, children: host })] }),
70
+ label: _jsxs(Text, { children: ["Si, y no volver a preguntar para ", _jsx(Text, { bold: true, children: host })] }),
71
71
  value: "yes-dont-ask-again"
72
72
  }] : [];
73
73
  $[4] = host;
@@ -79,7 +79,7 @@ export function SandboxPermissionRequest(t0) {
79
79
  let t6;
80
80
  if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
81
81
  t6 = {
82
- label: _jsxs(Text, { children: ["No, and tell Claude what to do differently ", _jsx(Text, { bold: true, children: "(esc)" })] }),
82
+ label: _jsxs(Text, { children: ["No, y decirle a Claude que hacer diferente ", _jsx(Text, { bold: true, children: "(esc)" })] }),
83
83
  value: "no"
84
84
  };
85
85
  $[6] = t6;
@@ -116,7 +116,7 @@ export function SandboxPermissionRequest(t0) {
116
116
  }
117
117
  let t10;
118
118
  if ($[12] === Symbol.for("react.memo_cache_sentinel")) {
119
- t10 = _jsx(Box, { marginTop: 1, children: _jsx(Text, { children: "Do you want to allow this connection?" }) });
119
+ t10 = _jsx(Box, { marginTop: 1, children: _jsx(Text, { children: "Deseas permitir esta conexion?" }) });
120
120
  $[12] = t10;
121
121
  }
122
122
  else {
@@ -149,7 +149,7 @@ export function SandboxPermissionRequest(t0) {
149
149
  }
150
150
  let t13;
151
151
  if ($[19] !== t12 || $[20] !== t9) {
152
- t13 = _jsx(PermissionDialog, { title: "Network request outside of sandbox", children: _jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [t9, t10, t12] }) });
152
+ t13 = _jsx(PermissionDialog, { title: "Solicitud de red fuera del sandbox", children: _jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [t9, t10, t12] }) });
153
153
  $[19] = t12;
154
154
  $[20] = t9;
155
155
  $[21] = t13;
@@ -1,76 +1,12 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { c as _c } from "react/compiler-runtime";
3
2
  import { Text } from '../../ink.js';
4
3
  import { useAppState } from '../../state/AppState.js';
5
- /**
6
- * Footer status indicator showing teammate count
7
- * Similar to BackgroundTaskStatus but for teammates
8
- */
9
- export function TeamStatus(t0) {
10
- const $ = _c(14);
11
- const { teamsSelected, showHint } = t0;
12
- const teamContext = useAppState(_temp);
13
- let t1;
14
- if ($[0] !== teamContext) {
15
- t1 = teamContext ? Object.values(teamContext.teammates).filter(_temp2).length : 0;
16
- $[0] = teamContext;
17
- $[1] = t1;
18
- }
19
- else {
20
- t1 = $[1];
21
- }
22
- const totalTeammates = t1;
23
- if (totalTeammates === 0) {
4
+ export function TeamStatus({ teamsSelected, showHint }) {
5
+ const teamContext = useAppState(s => s.teamContext);
6
+ const totalTeammates = teamContext ? Object.values(teamContext.teammates).filter(t => t.name !== 'team-lead').length : 0;
7
+ if (totalTeammates === 0)
24
8
  return null;
25
- }
26
- let t2;
27
- if ($[2] !== showHint || $[3] !== teamsSelected) {
28
- t2 = showHint && teamsSelected ? _jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: "\u00B7 " }), _jsx(Text, { dimColor: true, children: "Enter to view" })] }) : null;
29
- $[2] = showHint;
30
- $[3] = teamsSelected;
31
- $[4] = t2;
32
- }
33
- else {
34
- t2 = $[4];
35
- }
36
- const hint = t2;
37
- const statusText = `${totalTeammates} ${totalTeammates === 1 ? "teammate" : "teammates"}`;
38
- const t3 = teamsSelected ? "selected" : "normal";
39
- let t4;
40
- if ($[5] !== statusText || $[6] !== t3 || $[7] !== teamsSelected) {
41
- t4 = _jsx(Text, { color: "background", inverse: teamsSelected, children: statusText }, t3);
42
- $[5] = statusText;
43
- $[6] = t3;
44
- $[7] = teamsSelected;
45
- $[8] = t4;
46
- }
47
- else {
48
- t4 = $[8];
49
- }
50
- let t5;
51
- if ($[9] !== hint) {
52
- t5 = hint ? _jsxs(Text, { children: [" ", hint] }) : null;
53
- $[9] = hint;
54
- $[10] = t5;
55
- }
56
- else {
57
- t5 = $[10];
58
- }
59
- let t6;
60
- if ($[11] !== t4 || $[12] !== t5) {
61
- t6 = _jsxs(_Fragment, { children: [t4, t5] });
62
- $[11] = t4;
63
- $[12] = t5;
64
- $[13] = t6;
65
- }
66
- else {
67
- t6 = $[13];
68
- }
69
- return t6;
70
- }
71
- function _temp2(t) {
72
- return t.name !== "team-lead";
73
- }
74
- function _temp(s) {
75
- return s.teamContext;
9
+ const hint = showHint && teamsSelected ? _jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: "\u00B7 " }), _jsx(Text, { dimColor: true, children: "Enter para ver" })] }) : null;
10
+ const statusText = `${totalTeammates} ${totalTeammates === 1 ? 'agente' : 'agentes'}`;
11
+ return _jsxs(_Fragment, { children: [_jsx(Text, { color: "background", inverse: teamsSelected, children: statusText }, teamsSelected ? 'selected' : 'normal'), hint ? _jsxs(Text, { children: [" ", hint] }) : null] });
76
12
  }
@@ -12,191 +12,91 @@ export function getSpinnerVerbs() {
12
12
  }
13
13
  // Spinner verbs for loading messages
14
14
  export const SPINNER_VERBS = [
15
- 'Logrando',
16
- 'Accionando',
17
- 'Actualizando',
18
- 'Arquitectando',
19
- 'Horneando',
20
- 'Emitiendo',
21
- 'Beboppeando',
22
- 'Aturdiendo',
23
- 'Ondulando',
24
- 'Blanqueando',
25
- 'Fanfarroneando',
26
- 'Bailando',
27
- 'Malgastando',
28
- 'Boopeando',
29
- 'Inicializando',
30
- 'Preparando',
31
- 'Amasando',
32
- 'Agujereando',
15
+ 'Analizando',
33
16
  'Calculando',
34
- 'Enredando',
35
- 'Caramelizando',
36
- 'Cascada',
37
- 'Catapultando',
38
- 'Cerebrando',
39
- 'Canalizando',
40
- 'Canalizando',
41
- 'Coreografiando',
42
- 'Agitando',
43
- 'Contextualizando',
44
- 'Cohesionando',
45
- 'Cogitando',
46
- 'Organizando',
47
- 'Componiendo',
48
- 'Computando',
49
- 'Tramando',
50
- 'Considerando',
51
- 'Contemplando',
52
- 'Cocinando',
53
- 'Elaborando',
17
+ 'Compilando',
18
+ 'Configurando',
19
+ 'Conectando',
20
+ 'Construyendo',
21
+ 'Consultando',
22
+ 'Convirtiendo',
23
+ 'Corrigiendo',
54
24
  'Creando',
55
- 'Procesando',
56
- 'Cristalizando',
57
- 'Cultivando',
58
- 'Descifrando',
59
- 'Deliberando',
60
- 'Determinando',
61
- 'Entreteniendose',
62
- 'Desconcertando',
63
- 'Haciendo',
64
- 'Garabateando',
65
- 'Lloviznando',
66
- 'Menguando',
67
- 'Efectuando',
68
- 'Elucidando',
69
- 'Embelleciendo',
70
- 'Encantando',
71
- 'Imaginando',
72
- 'Evaporando',
73
- 'Fermentando',
74
- 'Pavoneando',
75
- 'Ingeniando',
76
- 'Flambeando',
77
- 'Parloteando',
78
- 'Fluyendo',
79
- 'Desconcertando',
80
- 'Aleteando',
81
- 'Forjando',
82
- 'Formando',
83
- 'Jugueteando',
84
- 'Glaseando',
85
- 'Callejeando',
86
- 'Galopando',
87
- 'Adornando',
25
+ 'Depurando',
26
+ 'Desplegando',
27
+ 'Detectando',
28
+ 'Diseñando',
29
+ 'Documentando',
30
+ 'Ejecutando',
31
+ 'Elaborando',
32
+ 'Evaluando',
33
+ 'Explorando',
88
34
  'Generando',
89
- 'Gesticulando',
90
- 'Germinando',
91
- 'Gitificando',
92
- 'Disfrutando',
93
- 'Soplando',
94
- 'Armonizando',
95
- 'Hasheando',
96
- 'Incubando',
97
- 'Pastoreando',
98
- 'Bocinando',
99
- 'Alborotando',
100
- 'Hiperespaciando',
101
- 'Ideando',
102
- 'Imaginando',
103
- 'Improvisando',
104
- 'Incubando',
105
- 'Infiriendo',
106
- 'Infusionando',
107
- 'Ionizando',
108
- 'Bailoteando',
109
- 'Cortando en juliana',
110
- 'Amasando',
111
- 'Leudando',
112
- 'Levitando',
113
- 'Vagueando',
114
- 'Manifestando',
115
- 'Marinando',
116
- 'Serpenteando',
117
- 'Metamorfoseando',
118
- 'Nublando',
119
- 'Caminando sobre la luna',
120
- 'Paseando',
121
- 'Reflexionando',
122
- 'Reuniendo',
123
- 'Meditando',
124
- 'Nebulizando',
125
- 'Anidando',
126
- 'Envolviendo',
127
- 'Enredando',
128
- 'Nucleando',
129
- 'Orbitando',
130
- 'Orquestando',
131
- 'Osmosando',
132
- 'Deambulando',
133
- 'Filtrando',
134
- 'Examinando',
135
- 'Filosofando',
136
- 'Fotosintetizando',
137
- 'Polinizando',
138
- 'Ponderando',
139
- 'Pontificando',
140
- 'Avalanzandose',
141
- 'Precipitando',
142
- 'Haciendo magia',
35
+ 'Identificando',
36
+ 'Implementando',
37
+ 'Indexando',
38
+ 'Inspeccionando',
39
+ 'Inicializando',
40
+ 'Integrando',
41
+ 'Investigando',
42
+ 'Optimizando',
43
+ 'Organizando',
44
+ 'Pensando',
45
+ 'Planificando',
46
+ 'Preparando',
143
47
  'Procesando',
48
+ 'Programando',
49
+ 'Proponiendo',
50
+ 'Razonando',
51
+ 'Refinando',
52
+ 'Reparando',
53
+ 'Resolviendo',
54
+ 'Revisando',
55
+ 'Sincronizando',
56
+ 'Sintetizando',
57
+ 'Transformando',
58
+ 'Validando',
144
59
  'Verificando',
145
- 'Propagando',
146
- 'Chapuceando',
147
- 'Intrigando',
148
- 'Cuantizando',
149
- 'Deslumbrando',
150
- 'Alborotando',
151
- 'Reorganizando',
152
- 'Reticulando',
153
- 'Anidando',
154
- 'Rumiando',
155
- 'Salteando',
156
- 'Correteando',
60
+ 'Versionando',
61
+ 'Vinculando',
62
+ 'Optando',
63
+ 'Afinando',
64
+ 'Modelando',
65
+ 'Mapeando',
66
+ 'Traduciendo',
67
+ 'Resumiendo',
68
+ 'Comparando',
69
+ 'Estructurando',
70
+ 'Ajustando',
71
+ 'Asistiendo',
72
+ 'Comprobando',
73
+ 'Monitoreando',
74
+ 'Priorizando',
75
+ 'Desglosando',
76
+ 'Uniendo',
77
+ 'Consolidando',
78
+ 'Preparando salida',
79
+ 'Finalizando',
80
+ 'Orquestando',
81
+ 'Enlazando',
82
+ 'Normalizando',
83
+ 'Resguardando',
84
+ 'Enrutando',
85
+ 'Confirmando',
86
+ 'Interpretando',
87
+ 'Rastreando',
88
+ 'Seleccionando',
89
+ 'Ordenando',
90
+ 'Actualizando',
91
+ 'Escaneando',
92
+ 'Extrayendo',
93
+ 'Limpiando',
94
+ 'Recopilando',
95
+ 'Diagnosticando',
96
+ 'Documentando cambios',
97
+ 'Comunicando',
98
+ 'Preparando respuesta',
99
+ 'Entregando',
157
100
  'Cargando',
158
- 'Escabullendose',
159
- 'Sazonando',
160
- 'Traveseando',
161
- 'Meneandose',
162
- 'Cociendo a fuego lento',
163
- 'Escapando',
164
- 'Bocetando',
165
- 'Deslizandose',
166
- 'Aplastando',
167
- 'Bailando en calcetines',
168
- 'Espeleologia',
169
- 'Girando',
170
- 'Brotando',
171
- 'Estofando',
172
- 'Sublimando',
173
- 'Remolinando',
174
- 'Planeando',
175
- 'Simbiotizando',
176
- 'Sintetizando',
177
- 'Templando',
178
- 'Pensando',
179
- 'Tronando',
180
- 'Trasteando',
181
- 'Haciendo tonterias',
182
- 'Poniendo del reves',
183
- 'Transfigurando',
184
- 'Transmutando',
185
- 'Retorciendo',
186
- 'Ondulando',
187
- 'Desplegando',
188
- 'Desenredando',
189
- 'Vibrando',
190
- 'Contoneandose',
191
- 'Vagando',
192
- 'Deformando',
193
- 'Chirimboleando',
194
- 'Remolinando',
195
- 'Zumbando',
196
- 'Batiendo',
197
- 'Tambaleando',
198
101
  'Trabajando',
199
- 'Disputando',
200
- 'Rallando',
201
- 'Zigzagueando',
202
102
  ];
@@ -0,0 +1,12 @@
1
+ import { createContext, useContext } from 'react';
2
+ const noop = () => { };
3
+ export const ModalStackContext = createContext({
4
+ stack: [],
5
+ pushModal: noop,
6
+ replaceModal: noop,
7
+ popModal: noop,
8
+ clearModals: noop
9
+ });
10
+ export function useModalStack() {
11
+ return useContext(ModalStackContext);
12
+ }
@@ -9,6 +9,16 @@ import { isFullscreenEnvEnabled } from '../utils/fullscreen.js';
9
9
  import { isModifierPressed, prewarmModifiers } from '../utils/modifiers.js';
10
10
  import { useDoublePress } from './useDoublePress.js';
11
11
  const NOOP_HANDLER = () => { };
12
+ function insertPlainText(cursor, input) {
13
+ const text = stripAnsi(input)
14
+ // eslint-disable-next-line custom-rules/no-lookbehind-regex -- .replace(re, str) on 1-2 char keystrokes: no-match returns same string (Object.is), regex never runs
15
+ .replace(/(?<=[^\\\r\n])\r$/, '')
16
+ .replace(/\r/g, '\n');
17
+ if (cursor.isAtStart() && isInputModeCharacter(input)) {
18
+ return cursor.insert(text).left();
19
+ }
20
+ return cursor.insert(text);
21
+ }
12
22
  function mapInput(input_map) {
13
23
  const map = new Map(input_map);
14
24
  return function (input) {
@@ -288,14 +298,7 @@ export function useTextInput({ value: originalValue, onChange, onSubmit, onExit,
288
298
  // Shift+Enter binding (pre-#8991 /terminal-setup wrote
289
299
  // args.text "\\\r\n" to keybindings.json); keep the \r so
290
300
  // it becomes \n below (anthropics/claude-code#31316).
291
- const text = stripAnsi(input)
292
- // eslint-disable-next-line custom-rules/no-lookbehind-regex -- .replace(re, str) on 1-2 char keystrokes: no-match returns same string (Object.is), regex never runs
293
- .replace(/(?<=[^\\\r\n])\r$/, '')
294
- .replace(/\r/g, '\n');
295
- if (cursor.isAtStart() && isInputModeCharacter(input)) {
296
- return cursor.insert(text).left();
297
- }
298
- return cursor.insert(text);
301
+ return insertPlainText(cursor, input);
299
302
  }
300
303
  }
301
304
  };
@@ -324,18 +327,25 @@ export function useTextInput({ value: originalValue, onChange, onSubmit, onExit,
324
327
  if (filteredInput === '' && input !== '') {
325
328
  return;
326
329
  }
327
- // Fix Issue #1853: Filter DEL characters that interfere with backspace in SSH/tmux
328
- // In SSH/tmux environments, backspace generates both key events and raw DEL chars
329
- if (!key.backspace && !key.delete && input.includes('\x7f')) {
330
- const delCount = (input.match(/\x7f/g) || []).length;
331
- // Apply all DEL characters as backspace operations synchronously
332
- // Try to delete tokens first, fall back to character backspace
330
+ // In SSH/tmux or slow terminals, raw DEL characters can be coalesced with
331
+ // printable input. Process the chunk sequentially so DEL only removes the
332
+ // preceding character and the rest of the packet still gets inserted.
333
+ if (!key.backspace && !key.delete && filteredInput.includes('\x7f')) {
333
334
  let currentCursor = cursor;
334
- for (let i = 0; i < delCount; i++) {
335
- currentCursor =
336
- currentCursor.deleteTokenBefore() ?? currentCursor.backspace();
335
+ let segmentStart = 0;
336
+ for (let i = 0; i < filteredInput.length; i++) {
337
+ if (filteredInput[i] !== '\x7f') {
338
+ continue;
339
+ }
340
+ if (segmentStart < i) {
341
+ currentCursor = insertPlainText(currentCursor, filteredInput.slice(segmentStart, i));
342
+ }
343
+ currentCursor = currentCursor.backspace();
344
+ segmentStart = i + 1;
345
+ }
346
+ if (segmentStart < filteredInput.length) {
347
+ currentCursor = insertPlainText(currentCursor, filteredInput.slice(segmentStart));
337
348
  }
338
- // Update state once with the final result
339
349
  if (!cursor.equals(currentCursor)) {
340
350
  if (cursor.text !== currentCursor.text) {
341
351
  onChange(currentCursor.text);
package/dist/src/main.js CHANGED
@@ -1451,6 +1451,18 @@ async function run() {
1451
1451
  catch (error) {
1452
1452
  logForDebugging(`[Database MCP] Setup failed: ${errorMessage(error)}`);
1453
1453
  }
1454
+ // Semble MCP: semantic code search for local and remote repositories.
1455
+ try {
1456
+ const { setupSembleMCP } = await import('./utils/sembleMcp/setup.js');
1457
+ const { mcpConfig: sembleMcpConfig } = setupSembleMCP();
1458
+ dynamicMcpConfig = {
1459
+ ...dynamicMcpConfig,
1460
+ ...sembleMcpConfig
1461
+ };
1462
+ }
1463
+ catch (error) {
1464
+ logForDebugging(`[Semble MCP] Setup failed: ${errorMessage(error)}`);
1465
+ }
1454
1466
  // Store additional directories for CLAUDE.md loading (controlled by env var)
1455
1467
  setAdditionalDirectoriesForClaudeMd(addDir);
1456
1468
  // Channel server allowlist from --channels flag — servers whose