stratum-cli 0.8.0-beta.0 → 0.8.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/index.js +167 -27
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,28 @@ El formato sigue [Keep a Changelog](https://keepachangelog.com/es-ES/1.1.0/) y l
|
|
|
6
6
|
|
|
7
7
|
> Las versiones anteriores a la 0.2.1-beta.0 solo existen como tags de git: la primera publicación en npm fue la 0.2.1-beta.0.
|
|
8
8
|
|
|
9
|
+
## [0.8.0-beta.2] — 2026-10-12
|
|
10
|
+
|
|
11
|
+
Tercera pre-release (`npm install -g stratum-cli@beta`), con más arreglos de lo visto al probar la beta.
|
|
12
|
+
|
|
13
|
+
### Corregido
|
|
14
|
+
- **El terminal parpadeaba con varios subagentes trabajando.** El árbol de subagentes listaba todas sus tool calls; al superar el alto del terminal, la pantalla entera se borraba y repintaba en cada actualización. Ahora cada subagente enseña solo las últimas (entre 1 y 6, según el alto del terminal) y resume las anteriores en una línea; el detalle completo sigue en `/subagents`.
|
|
15
|
+
- La etiqueta de una tool call enseña el argumento que la identifica (la ruta, el comando, el patrón) aunque el modelo lo envíe detrás de otros: antes salía `read_file: 700` cuando `limit` llegaba antes que `path`.
|
|
16
|
+
- Dos sesiones nuevas guardadas en el mismo segundo podían recibir el mismo id y la segunda pisaba a la primera. Ahora el id generado se comprueba contra el disco.
|
|
17
|
+
|
|
18
|
+
## [0.8.0-beta.1] — 2026-10-12
|
|
19
|
+
|
|
20
|
+
Segunda pre-release (`npm install -g stratum-cli@beta`), con lo visto al probar la beta.0.
|
|
21
|
+
|
|
22
|
+
### Añadido
|
|
23
|
+
- **`/comandos` con el agente trabajando**: los de consulta (`/context`, `/jobs`, `/jobs cancel`, `/todo`, `/changes`, `/auditor`, `/debug`, `/tools`, `/agents`, `/env`, `/memory show|list|search`, `/sessions list`, `/config get`, `/help`) se ejecutan sin esperar al final del turno, y la paleta se reduce a ellos. Los que tocan el historial, el modelo o el toolset siguen esperando.
|
|
24
|
+
|
|
25
|
+
### Corregido
|
|
26
|
+
- **La salida de un comando ya no se vuelca en la pantalla del chat.** Cuando un `exec` fallaba, el log escribía su salida completa en el terminal, encima de la interfaz. Ahora un comando que se ejecutó y salió mal no se registra como aviso, y cualquier campo del log que vaya al terminal sale en una línea y acotado a 300 caracteres; el fichero de logs lo guarda entero.
|
|
27
|
+
- El texto de dos respuestas del mismo turno, con una tool o una pregunta por medio, ya no sale pegado («…rápidas:Perfecto…»): la segunda empieza párrafo.
|
|
28
|
+
- El bloque de la tool `question` mostraba `[object Object],[object Object]`; ahora enseña la primera pregunta y cuántas más hay.
|
|
29
|
+
- `Ctrl+U` y `Ctrl+T` podían dejar su letra escrita en el input en vez de actuar, y `Ctrl+L` limpiaba la conversación con un turno en curso.
|
|
30
|
+
|
|
9
31
|
## [0.8.0-beta.0] — 2026-10-12
|
|
10
32
|
|
|
11
33
|
Pre-release para pruebas (`npm install -g stratum-cli@beta`); `latest` sigue en la 0.7.0.
|
|
@@ -271,6 +293,8 @@ Primera versión etiquetada. Hitos 0 y 1.
|
|
|
271
293
|
- `/init` para generar o actualizar `STRATUM.md`.
|
|
272
294
|
- Render de markdown de las respuestas.
|
|
273
295
|
|
|
296
|
+
[0.8.0-beta.2]: https://github.com/choruzo/CLI/compare/v0.8.0-beta.1...v0.8.0-beta.2
|
|
297
|
+
[0.8.0-beta.1]: https://github.com/choruzo/CLI/compare/v0.8.0-beta.0...v0.8.0-beta.1
|
|
274
298
|
[0.8.0-beta.0]: https://github.com/choruzo/CLI/compare/v0.7.0...v0.8.0-beta.0
|
|
275
299
|
[0.7.0]: https://github.com/choruzo/CLI/compare/v0.6.0...v0.7.0
|
|
276
300
|
[0.7.0-beta.0]: https://github.com/choruzo/CLI/compare/v0.6.0...v0.7.0-beta.0
|
package/dist/index.js
CHANGED
|
@@ -1305,17 +1305,22 @@ import { dirname as dirname2 } from "path";
|
|
|
1305
1305
|
function ansi(code) {
|
|
1306
1306
|
return (s) => `\x1B[${code}m${s}\x1B[0m`;
|
|
1307
1307
|
}
|
|
1308
|
+
function formatFieldValue(v) {
|
|
1309
|
+
const raw = typeof v === "string" ? v : typeof v === "object" ? JSON.stringify(v) : String(v);
|
|
1310
|
+
const flat = raw.replace(/\s*[\r\n]+\s*/g, " \u23CE ");
|
|
1311
|
+
if (flat.length <= STDERR_FIELD_MAX_CHARS) return flat;
|
|
1312
|
+
return `${flat.slice(0, STDERR_FIELD_MAX_CHARS)}\u2026 (+${flat.length - STDERR_FIELD_MAX_CHARS} chars)`;
|
|
1313
|
+
}
|
|
1308
1314
|
function formatFields(fields) {
|
|
1309
1315
|
if (!fields) return "";
|
|
1310
1316
|
const parts = [];
|
|
1311
1317
|
for (const [k, v] of Object.entries(fields)) {
|
|
1312
1318
|
if (v === void 0) continue;
|
|
1313
|
-
|
|
1314
|
-
parts.push(`${k}=${val}`);
|
|
1319
|
+
parts.push(`${k}=${formatFieldValue(v)}`);
|
|
1315
1320
|
}
|
|
1316
1321
|
return parts.length > 0 ? " " + parts.join(" ") : "";
|
|
1317
1322
|
}
|
|
1318
|
-
var NO_COLOR, LEVEL_COLOR, LEVEL_LABEL, StderrSink, FileSink;
|
|
1323
|
+
var NO_COLOR, LEVEL_COLOR, LEVEL_LABEL, STDERR_FIELD_MAX_CHARS, StderrSink, FileSink;
|
|
1319
1324
|
var init_sinks = __esm({
|
|
1320
1325
|
"src/logging/sinks.ts"() {
|
|
1321
1326
|
"use strict";
|
|
@@ -1341,6 +1346,7 @@ var init_sinks = __esm({
|
|
|
1341
1346
|
warn: "WARN ",
|
|
1342
1347
|
error: "ERROR"
|
|
1343
1348
|
};
|
|
1349
|
+
STDERR_FIELD_MAX_CHARS = 300;
|
|
1344
1350
|
StderrSink = class {
|
|
1345
1351
|
level;
|
|
1346
1352
|
stream;
|
|
@@ -5589,7 +5595,8 @@ Tool "${name}" has been disabled for this session after ${failures} consecutive
|
|
|
5589
5595
|
if (result.ok) {
|
|
5590
5596
|
log3.debug("tool ok", { tool: call.name, durationMs, outputChars: result.output.length });
|
|
5591
5597
|
} else {
|
|
5592
|
-
|
|
5598
|
+
const level = result.countsAsFailure === false ? "info" : "warn";
|
|
5599
|
+
log3[level]("tool error", {
|
|
5593
5600
|
tool: call.name,
|
|
5594
5601
|
durationMs,
|
|
5595
5602
|
recoverable: result.recoverable,
|
|
@@ -19719,6 +19726,16 @@ var init_store2 = __esm({
|
|
|
19719
19726
|
mkdirSync7(this.sessionsDir, { recursive: true });
|
|
19720
19727
|
}
|
|
19721
19728
|
}
|
|
19729
|
+
/**
|
|
19730
|
+
* Un id que no está en disco. El id lleva la hora al segundo y tres
|
|
19731
|
+
* caracteres al azar: dos sesiones guardadas en el mismo segundo pueden
|
|
19732
|
+
* coincidir, y la segunda pisaría a la primera.
|
|
19733
|
+
*/
|
|
19734
|
+
freshSessionId() {
|
|
19735
|
+
let id = generateSessionId();
|
|
19736
|
+
while (existsSync16(this.sessionPath(id))) id = generateSessionId();
|
|
19737
|
+
return id;
|
|
19738
|
+
}
|
|
19722
19739
|
sessionPath(id) {
|
|
19723
19740
|
if (!isSessionId(id)) {
|
|
19724
19741
|
throw new Error(`Id de sesi\xF3n inv\xE1lido: ${JSON.stringify(id.slice(0, 80))}`);
|
|
@@ -19740,14 +19757,14 @@ var init_store2 = __esm({
|
|
|
19740
19757
|
async save(params) {
|
|
19741
19758
|
this.ensureDir();
|
|
19742
19759
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
19743
|
-
let id = params.existingId ??
|
|
19760
|
+
let id = params.existingId ?? this.freshSessionId();
|
|
19744
19761
|
let createdAt = params.createdAt ?? now;
|
|
19745
19762
|
let forkedFrom = params.forkedFrom;
|
|
19746
19763
|
if (params.existingId) {
|
|
19747
19764
|
const onDisk = this.diskUpdatedAt(params.existingId);
|
|
19748
19765
|
if (onDisk !== null && onDisk !== params.expectedUpdatedAt) {
|
|
19749
19766
|
forkedFrom = params.existingId;
|
|
19750
|
-
id =
|
|
19767
|
+
id = this.freshSessionId();
|
|
19751
19768
|
createdAt = now;
|
|
19752
19769
|
log21.warn("session changed on disk: saving as a fork", { from: forkedFrom, to: id });
|
|
19753
19770
|
}
|
|
@@ -20774,6 +20791,51 @@ var init_spinner = __esm({
|
|
|
20774
20791
|
}
|
|
20775
20792
|
});
|
|
20776
20793
|
|
|
20794
|
+
// src/cli/ui/tool-arg-label.ts
|
|
20795
|
+
function labelOf(value2) {
|
|
20796
|
+
if (value2 === null || value2 === void 0) return "";
|
|
20797
|
+
if (typeof value2 !== "object") return String(value2);
|
|
20798
|
+
if (!Array.isArray(value2)) return JSON.stringify(value2);
|
|
20799
|
+
const first = value2[0];
|
|
20800
|
+
const head = typeof first === "object" && first !== null ? Object.values(first).find((v) => typeof v === "string") ?? JSON.stringify(first) : String(first ?? "");
|
|
20801
|
+
return value2.length > 1 ? `${head} (+${value2.length - 1})` : head;
|
|
20802
|
+
}
|
|
20803
|
+
function primaryArg(input) {
|
|
20804
|
+
if (!input) return "";
|
|
20805
|
+
const keys = Object.keys(input);
|
|
20806
|
+
if (keys.length === 0) return "";
|
|
20807
|
+
const key = IDENTIFYING_KEYS.find((k) => typeof input[k] === "string" && input[k] !== "") ?? keys[0];
|
|
20808
|
+
return labelOf(input[key]);
|
|
20809
|
+
}
|
|
20810
|
+
function tailWindow(items, max) {
|
|
20811
|
+
const keep = Math.max(1, Math.floor(max));
|
|
20812
|
+
if (items.length <= keep) return { hidden: 0, visible: [...items] };
|
|
20813
|
+
return { hidden: items.length - keep, visible: items.slice(-keep) };
|
|
20814
|
+
}
|
|
20815
|
+
function treeToolBudget(rows, nodes, reservedRows = 22) {
|
|
20816
|
+
const perNode = Math.floor((rows - reservedRows) / Math.max(1, nodes)) - 2;
|
|
20817
|
+
return Math.min(6, Math.max(1, perNode));
|
|
20818
|
+
}
|
|
20819
|
+
var IDENTIFYING_KEYS;
|
|
20820
|
+
var init_tool_arg_label = __esm({
|
|
20821
|
+
"src/cli/ui/tool-arg-label.ts"() {
|
|
20822
|
+
"use strict";
|
|
20823
|
+
init_esm_shims();
|
|
20824
|
+
IDENTIFYING_KEYS = [
|
|
20825
|
+
"command",
|
|
20826
|
+
"path",
|
|
20827
|
+
"file_path",
|
|
20828
|
+
"filePath",
|
|
20829
|
+
"pattern",
|
|
20830
|
+
"query",
|
|
20831
|
+
"url",
|
|
20832
|
+
"task",
|
|
20833
|
+
"jobId",
|
|
20834
|
+
"name"
|
|
20835
|
+
];
|
|
20836
|
+
}
|
|
20837
|
+
});
|
|
20838
|
+
|
|
20777
20839
|
// src/cli/ui/ToolCallBlock.tsx
|
|
20778
20840
|
import { Box, Text } from "ink";
|
|
20779
20841
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -20804,7 +20866,7 @@ function formatInput(state) {
|
|
|
20804
20866
|
return truncateLabel(`${from} \u2192 ${to}`);
|
|
20805
20867
|
}
|
|
20806
20868
|
}
|
|
20807
|
-
return truncateLabel(
|
|
20869
|
+
return truncateLabel(primaryArg(src));
|
|
20808
20870
|
}
|
|
20809
20871
|
function formatDuration(ms) {
|
|
20810
20872
|
return `${(ms / 1e3).toFixed(1)}s`;
|
|
@@ -20925,6 +20987,7 @@ var init_ToolCallBlock = __esm({
|
|
|
20925
20987
|
init_esm_shims();
|
|
20926
20988
|
init_theme();
|
|
20927
20989
|
init_spinner();
|
|
20990
|
+
init_tool_arg_label();
|
|
20928
20991
|
MAX_EXPANDED_LINES = 10;
|
|
20929
20992
|
SLOW_MS = 1e3;
|
|
20930
20993
|
}
|
|
@@ -21663,6 +21726,19 @@ var init_CommandPalette = __esm({
|
|
|
21663
21726
|
});
|
|
21664
21727
|
|
|
21665
21728
|
// src/cli/ui/session-commands.ts
|
|
21729
|
+
function matchCommand(input, commands = SESSION_COMMANDS) {
|
|
21730
|
+
const line = input.trim();
|
|
21731
|
+
let best = null;
|
|
21732
|
+
for (const c of commands) {
|
|
21733
|
+
if (line !== c.name && !line.startsWith(c.name + " ")) continue;
|
|
21734
|
+
if (!best || c.name.length > best.name.length) best = c;
|
|
21735
|
+
}
|
|
21736
|
+
return best;
|
|
21737
|
+
}
|
|
21738
|
+
function isBusyCommand(input) {
|
|
21739
|
+
const match = matchCommand(input);
|
|
21740
|
+
return match !== null && BUSY_COMMAND_NAMES.has(match.name);
|
|
21741
|
+
}
|
|
21666
21742
|
function filterCommands(input, commands = SESSION_COMMANDS) {
|
|
21667
21743
|
const trimmed = input.trimStart();
|
|
21668
21744
|
if (!trimmed.startsWith("/")) return [];
|
|
@@ -21679,7 +21755,7 @@ function filterProfiles(input, profiles) {
|
|
|
21679
21755
|
function slashCommandName(input) {
|
|
21680
21756
|
return /^(\/[A-Za-z][\w-]*)(\s|$)/.exec(input.trimStart())?.[1] ?? null;
|
|
21681
21757
|
}
|
|
21682
|
-
var SESSION_COMMANDS;
|
|
21758
|
+
var SESSION_COMMANDS, BUSY_COMMAND_NAMES, BUSY_COMMANDS;
|
|
21683
21759
|
var init_session_commands = __esm({
|
|
21684
21760
|
"src/cli/ui/session-commands.ts"() {
|
|
21685
21761
|
"use strict";
|
|
@@ -21849,6 +21925,28 @@ var init_session_commands = __esm({
|
|
|
21849
21925
|
{ name: "/quit", description: "Termina la sesi\xF3n y guarda el historial", hasArgs: false },
|
|
21850
21926
|
{ name: "/exit", description: "Termina la sesi\xF3n y guarda el historial", hasArgs: false }
|
|
21851
21927
|
];
|
|
21928
|
+
BUSY_COMMAND_NAMES = /* @__PURE__ */ new Set([
|
|
21929
|
+
"/help",
|
|
21930
|
+
"/context",
|
|
21931
|
+
"/todo",
|
|
21932
|
+
"/changes",
|
|
21933
|
+
"/jobs",
|
|
21934
|
+
"/jobs cancel",
|
|
21935
|
+
"/auditor",
|
|
21936
|
+
"/auditor stop",
|
|
21937
|
+
"/debug",
|
|
21938
|
+
"/tools",
|
|
21939
|
+
"/agents",
|
|
21940
|
+
"/env",
|
|
21941
|
+
"/memory show",
|
|
21942
|
+
"/memory list",
|
|
21943
|
+
"/memory search",
|
|
21944
|
+
"/sessions list",
|
|
21945
|
+
"/config get"
|
|
21946
|
+
]);
|
|
21947
|
+
BUSY_COMMANDS = SESSION_COMMANDS.filter(
|
|
21948
|
+
(c) => BUSY_COMMAND_NAMES.has(c.name)
|
|
21949
|
+
);
|
|
21852
21950
|
}
|
|
21853
21951
|
});
|
|
21854
21952
|
|
|
@@ -22348,7 +22446,7 @@ var init_SubagentBlock = __esm({
|
|
|
22348
22446
|
});
|
|
22349
22447
|
|
|
22350
22448
|
// src/cli/ui/AgentTree.tsx
|
|
22351
|
-
import { Box as Box12, Text as Text13 } from "ink";
|
|
22449
|
+
import { Box as Box12, Text as Text13, useStdout as useStdout3 } from "ink";
|
|
22352
22450
|
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
22353
22451
|
function fmtDur2(ms) {
|
|
22354
22452
|
return `${(ms / 1e3).toFixed(1)}s`;
|
|
@@ -22358,10 +22456,7 @@ function truncate2(text, max) {
|
|
|
22358
22456
|
return oneLine.length > max ? oneLine.slice(0, max - 1) + "\u2026" : oneLine;
|
|
22359
22457
|
}
|
|
22360
22458
|
function firstArg(tc) {
|
|
22361
|
-
|
|
22362
|
-
const keys = Object.keys(src);
|
|
22363
|
-
if (keys.length === 0) return "";
|
|
22364
|
-
return truncate2(String(src[keys[0]] ?? ""), 40);
|
|
22459
|
+
return truncate2(primaryArg(tc.input), 40);
|
|
22365
22460
|
}
|
|
22366
22461
|
function ToolLine({ tc }) {
|
|
22367
22462
|
const icon = tc.status === "completed" ? "\u2713" : tc.status === "error" ? "\u2717" : "\u27F3";
|
|
@@ -22396,7 +22491,7 @@ function nodeIcon(status) {
|
|
|
22396
22491
|
return { icon: "\u22B3", color: theme.accent };
|
|
22397
22492
|
}
|
|
22398
22493
|
}
|
|
22399
|
-
function SubagentNode({ node, speaking, focused, expanded, isLast, now }) {
|
|
22494
|
+
function SubagentNode({ node, speaking, focused, expanded, isLast, now, maxToolLines }) {
|
|
22400
22495
|
const running = node.status === "running";
|
|
22401
22496
|
const elapsedMs = node.startedAt ? Math.max(0, now - node.startedAt) : 0;
|
|
22402
22497
|
const { icon, color } = nodeIcon(node.status);
|
|
@@ -22408,7 +22503,7 @@ function SubagentNode({ node, speaking, focused, expanded, isLast, now }) {
|
|
|
22408
22503
|
node.iterations !== void 0 ? `${node.iterations} it` : ""
|
|
22409
22504
|
].filter(Boolean).join(" \xB7 ");
|
|
22410
22505
|
const tail2 = node.status === "failed" && node.error ? truncate2(node.error, 44) : node.status === "completed" && node.summary ? truncate2(node.summary, 44) : truncate2(node.task, 44);
|
|
22411
|
-
const tcs = node.toolCalls ?? [];
|
|
22506
|
+
const { hidden, visible: tcs } = tailWindow(node.toolCalls ?? [], maxToolLines);
|
|
22412
22507
|
const files = node.filesChanged ?? [];
|
|
22413
22508
|
return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", children: [
|
|
22414
22509
|
/* @__PURE__ */ jsxs11(Text13, { wrap: "truncate-end", children: [
|
|
@@ -22432,6 +22527,15 @@ function SubagentNode({ node, speaking, focused, expanded, isLast, now }) {
|
|
|
22432
22527
|
] }),
|
|
22433
22528
|
focused ? /* @__PURE__ */ jsx13(Text13, { color: theme.accent, children: " \u25C0" }) : null
|
|
22434
22529
|
] }),
|
|
22530
|
+
hidden > 0 && /* @__PURE__ */ jsxs11(Text13, { color: theme.textDisabled, wrap: "truncate-end", children: [
|
|
22531
|
+
" ",
|
|
22532
|
+
"\u2026 ",
|
|
22533
|
+
hidden,
|
|
22534
|
+
" ",
|
|
22535
|
+
hidden === 1 ? "acci\xF3n anterior" : "acciones anteriores",
|
|
22536
|
+
" ",
|
|
22537
|
+
"(/subagents para verlas)"
|
|
22538
|
+
] }),
|
|
22435
22539
|
tcs.map((tc) => /* @__PURE__ */ jsx13(ToolLine, { tc }, tc.id)),
|
|
22436
22540
|
expanded && node.summary && /* @__PURE__ */ jsxs11(Text13, { color: theme.textFaint, wrap: "truncate-end", children: [
|
|
22437
22541
|
" ",
|
|
@@ -22457,6 +22561,8 @@ function AgentTree({
|
|
|
22457
22561
|
expandedBlockIds,
|
|
22458
22562
|
now = Date.now()
|
|
22459
22563
|
}) {
|
|
22564
|
+
const { stdout } = useStdout3();
|
|
22565
|
+
const maxToolLines = treeToolBudget(stdout?.rows ?? 24, nodes.length);
|
|
22460
22566
|
const allTerminal = nodes.every((n) => TERMINAL.has(n.status));
|
|
22461
22567
|
if (allTerminal) {
|
|
22462
22568
|
const completed = nodes.filter((n) => n.status === "completed").length;
|
|
@@ -22502,7 +22608,8 @@ function AgentTree({
|
|
|
22502
22608
|
focused: focusedBlockId === n.id,
|
|
22503
22609
|
expanded: expandedBlockIds?.has(n.id) ?? false,
|
|
22504
22610
|
isLast: i === nodes.length - 1,
|
|
22505
|
-
now
|
|
22611
|
+
now,
|
|
22612
|
+
maxToolLines
|
|
22506
22613
|
},
|
|
22507
22614
|
n.id
|
|
22508
22615
|
))
|
|
@@ -22515,6 +22622,7 @@ var init_AgentTree = __esm({
|
|
|
22515
22622
|
init_esm_shims();
|
|
22516
22623
|
init_theme();
|
|
22517
22624
|
init_spinner();
|
|
22625
|
+
init_tool_arg_label();
|
|
22518
22626
|
TERMINAL = /* @__PURE__ */ new Set([
|
|
22519
22627
|
"completed",
|
|
22520
22628
|
"failed",
|
|
@@ -22736,7 +22844,7 @@ var init_AgentMessage = __esm({
|
|
|
22736
22844
|
});
|
|
22737
22845
|
|
|
22738
22846
|
// src/cli/ui/MessageList.tsx
|
|
22739
|
-
import { Box as Box15, Static as Static2, useStdout as
|
|
22847
|
+
import { Box as Box15, Static as Static2, useStdout as useStdout4 } from "ink";
|
|
22740
22848
|
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
22741
22849
|
function renderItem(item, key, focusedBlockId, expandedBlockIds, debug, now, liveTextLines, liveColumns, liveActionLimit) {
|
|
22742
22850
|
if (item.kind === "user") {
|
|
@@ -22786,7 +22894,7 @@ function MessageList({
|
|
|
22786
22894
|
now = Date.now(),
|
|
22787
22895
|
availableRows
|
|
22788
22896
|
}) {
|
|
22789
|
-
const { stdout } =
|
|
22897
|
+
const { stdout } = useStdout4();
|
|
22790
22898
|
const { contentWidth } = resolveLayout(stdout.columns ?? 80, stdout.rows ?? 24);
|
|
22791
22899
|
const terminalRows = availableRows ?? stdout.rows ?? 24;
|
|
22792
22900
|
const liveActionLimit = Math.max(1, Math.min(6, Math.floor((terminalRows - 8) / 2)));
|
|
@@ -23513,7 +23621,7 @@ var init_FatalError = __esm({
|
|
|
23513
23621
|
});
|
|
23514
23622
|
|
|
23515
23623
|
// src/cli/ui/ConversationView.tsx
|
|
23516
|
-
import { Box as Box26, Text as Text27, useStdout as
|
|
23624
|
+
import { Box as Box26, Text as Text27, useStdout as useStdout5 } from "ink";
|
|
23517
23625
|
import { jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
23518
23626
|
function ConversationView({
|
|
23519
23627
|
completedItems,
|
|
@@ -23563,7 +23671,7 @@ function ConversationView({
|
|
|
23563
23671
|
const liveNow = useLiveClock(thinking);
|
|
23564
23672
|
const gateOpen = !!pendingConfirm || !!pendingQuestions?.length || !!pendingApproval;
|
|
23565
23673
|
const steerable = thinking && !gateOpen && !fatalError;
|
|
23566
|
-
const { stdout } =
|
|
23674
|
+
const { stdout } = useStdout5();
|
|
23567
23675
|
const terminalRows = stdout.rows ?? 24;
|
|
23568
23676
|
const panelMaxSteps = Math.max(2, Math.min(5, Math.floor(terminalRows / 5)));
|
|
23569
23677
|
const jobsClock = jobsNow ?? Date.now();
|
|
@@ -24677,12 +24785,21 @@ function reducer(state, action) {
|
|
|
24677
24785
|
}
|
|
24678
24786
|
case "AGENT_EVENT": {
|
|
24679
24787
|
const ev = action.event;
|
|
24788
|
+
if (/^(tool_|subagent_|questions_|plan_)/.test(ev.type) && state.currentItem?.kind === "agent" && state.currentItem.text && !state.currentItem.textBreak) {
|
|
24789
|
+
return reducer(
|
|
24790
|
+
{ ...state, currentItem: { ...state.currentItem, textBreak: true } },
|
|
24791
|
+
action
|
|
24792
|
+
);
|
|
24793
|
+
}
|
|
24680
24794
|
if (ev.type === "text_delta") {
|
|
24681
24795
|
return {
|
|
24682
24796
|
...state,
|
|
24683
24797
|
currentItem: updateCurrentAgent(state.currentItem, (item) => ({
|
|
24684
24798
|
...item,
|
|
24685
|
-
text: item.
|
|
24799
|
+
text: item.textBreak ? `${item.text.trimEnd()}
|
|
24800
|
+
|
|
24801
|
+
${ev.delta}` : item.text + ev.delta,
|
|
24802
|
+
textBreak: false,
|
|
24686
24803
|
thinkingOpen: false
|
|
24687
24804
|
}))
|
|
24688
24805
|
};
|
|
@@ -25294,8 +25411,8 @@ function App({
|
|
|
25294
25411
|
const [subagentViewHint, setSubagentViewHint] = useState9(null);
|
|
25295
25412
|
const [paletteIndex, setPaletteIndex] = useState9(0);
|
|
25296
25413
|
const [paletteDismissed, setPaletteDismissed] = useState9(false);
|
|
25297
|
-
const paletteEligible = !state.
|
|
25298
|
-
const paletteItems = !paletteEligible ? [] : state.inputValue.trimStart().startsWith("@") ? filterProfiles(state.inputValue, profileRows) : filterCommands(state.inputValue, SESSION_COMMANDS);
|
|
25414
|
+
const paletteEligible = !state.pendingConfirm && !state.pendingQuestions && !overlay && state.focusState === "input" && !paletteDismissed && /^[/@]/.test(state.inputValue.trimStart());
|
|
25415
|
+
const paletteItems = !paletteEligible ? [] : state.inputValue.trimStart().startsWith("@") ? state.thinking ? [] : filterProfiles(state.inputValue, profileRows) : filterCommands(state.inputValue, state.thinking ? BUSY_COMMANDS : SESSION_COMMANDS);
|
|
25299
25416
|
const effPaletteIndex = Math.min(paletteIndex, Math.max(paletteItems.length - 1, 0));
|
|
25300
25417
|
const handleInputChange = useCallback4((value2) => {
|
|
25301
25418
|
setPaletteDismissed(false);
|
|
@@ -25390,18 +25507,28 @@ function App({
|
|
|
25390
25507
|
return;
|
|
25391
25508
|
}
|
|
25392
25509
|
}
|
|
25510
|
+
const settleInput = (value2) => {
|
|
25511
|
+
setTimeout(() => dispatch({ type: "INPUT_CHANGE", value: value2 }), 0);
|
|
25512
|
+
};
|
|
25393
25513
|
if (key.ctrl && input === "l") {
|
|
25514
|
+
if (state.thinking) {
|
|
25515
|
+
settleInput(state.inputValue);
|
|
25516
|
+
return;
|
|
25517
|
+
}
|
|
25394
25518
|
executeCommandRef.current?.("/clear");
|
|
25519
|
+
settleInput("");
|
|
25395
25520
|
return;
|
|
25396
25521
|
}
|
|
25397
25522
|
if (key.ctrl && input === "t") {
|
|
25398
25523
|
dispatch({ type: "TOGGLE_TODO" });
|
|
25524
|
+
settleInput(state.inputValue);
|
|
25399
25525
|
return;
|
|
25400
25526
|
}
|
|
25401
25527
|
if (key.ctrl && input === "u") {
|
|
25402
25528
|
draftRef.current = "";
|
|
25403
25529
|
setHistoryIndex(null);
|
|
25404
25530
|
dispatch({ type: "INPUT_CHANGE", value: "" });
|
|
25531
|
+
settleInput("");
|
|
25405
25532
|
return;
|
|
25406
25533
|
}
|
|
25407
25534
|
if (state.focusState === "input" && (key.upArrow || key.downArrow)) {
|
|
@@ -26401,7 +26528,20 @@ Uso: /provider <alias> para cambiar en esta sesi\xF3n \xB7 /provider remove <ali
|
|
|
26401
26528
|
}
|
|
26402
26529
|
if (state.thinking) {
|
|
26403
26530
|
if (/^[/@]/.test(cmd)) {
|
|
26404
|
-
|
|
26531
|
+
const sel = paletteItems[effPaletteIndex];
|
|
26532
|
+
if (sel && sel.name !== cmd) {
|
|
26533
|
+
if (sel.hasArgs) completePaletteSelection(sel.name, true);
|
|
26534
|
+
else executeCommand(sel.name);
|
|
26535
|
+
return;
|
|
26536
|
+
}
|
|
26537
|
+
if (isBusyCommand(cmd)) {
|
|
26538
|
+
setInputHint(null);
|
|
26539
|
+
executeCommand(cmd);
|
|
26540
|
+
return;
|
|
26541
|
+
}
|
|
26542
|
+
setInputHint(
|
|
26543
|
+
"Not available while the agent is working (Ctrl+C cancels). Type / to see what is."
|
|
26544
|
+
);
|
|
26405
26545
|
return;
|
|
26406
26546
|
}
|
|
26407
26547
|
setInputHint(null);
|
|
@@ -26879,7 +27019,7 @@ async function settle(step, fn) {
|
|
|
26879
27019
|
}
|
|
26880
27020
|
}
|
|
26881
27021
|
function resolveVersion() {
|
|
26882
|
-
if (true) return "0.8.0-beta.
|
|
27022
|
+
if (true) return "0.8.0-beta.2";
|
|
26883
27023
|
try {
|
|
26884
27024
|
const thisDir = dirname14(fileURLToPath2(import.meta.url));
|
|
26885
27025
|
const pkg = JSON.parse(
|
|
@@ -32734,7 +32874,7 @@ function resolveResult(ref, dir) {
|
|
|
32734
32874
|
}
|
|
32735
32875
|
|
|
32736
32876
|
// src/cli/commands/eval.ts
|
|
32737
|
-
var VERSION = true ? "0.8.0-beta.
|
|
32877
|
+
var VERSION = true ? "0.8.0-beta.2" : "dev";
|
|
32738
32878
|
var fail2 = (message) => {
|
|
32739
32879
|
process.stderr.write(`${message}
|
|
32740
32880
|
`);
|
|
@@ -33347,7 +33487,7 @@ var statsCommand = new Command14("stats").description(
|
|
|
33347
33487
|
init_loader();
|
|
33348
33488
|
init_schema_version();
|
|
33349
33489
|
function resolveVersion2() {
|
|
33350
|
-
if (true) return "0.8.0-beta.
|
|
33490
|
+
if (true) return "0.8.0-beta.2";
|
|
33351
33491
|
const thisDir = dirname19(fileURLToPath5(import.meta.url));
|
|
33352
33492
|
const pkg = JSON.parse(readFileSync26(join32(thisDir, "..", "..", "package.json"), "utf-8"));
|
|
33353
33493
|
return pkg.version;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stratum-cli",
|
|
3
|
-
"version": "0.8.0-beta.
|
|
3
|
+
"version": "0.8.0-beta.2",
|
|
4
4
|
"description": "Agente CLI extensible sobre un loop ReAct — provider-agnostic (Ollama, llama.cpp, vLLM, LiteLLM, OpenAI), con plan-and-execute, subagentes, MCP y SSH nativo",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|