stratum-cli 0.8.0-beta.0 → 0.8.0-beta.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.
- package/CHANGELOG.md +14 -0
- package/dist/index.js +95 -13
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,19 @@ 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.1] — 2026-10-12
|
|
10
|
+
|
|
11
|
+
Segunda pre-release (`npm install -g stratum-cli@beta`), con lo visto al probar la beta.0.
|
|
12
|
+
|
|
13
|
+
### Añadido
|
|
14
|
+
- **`/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.
|
|
15
|
+
|
|
16
|
+
### Corregido
|
|
17
|
+
- **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.
|
|
18
|
+
- 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.
|
|
19
|
+
- El bloque de la tool `question` mostraba `[object Object],[object Object]`; ahora enseña la primera pregunta y cuántas más hay.
|
|
20
|
+
- `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.
|
|
21
|
+
|
|
9
22
|
## [0.8.0-beta.0] — 2026-10-12
|
|
10
23
|
|
|
11
24
|
Pre-release para pruebas (`npm install -g stratum-cli@beta`); `latest` sigue en la 0.7.0.
|
|
@@ -271,6 +284,7 @@ Primera versión etiquetada. Hitos 0 y 1.
|
|
|
271
284
|
- `/init` para generar o actualizar `STRATUM.md`.
|
|
272
285
|
- Render de markdown de las respuestas.
|
|
273
286
|
|
|
287
|
+
[0.8.0-beta.1]: https://github.com/choruzo/CLI/compare/v0.8.0-beta.0...v0.8.0-beta.1
|
|
274
288
|
[0.8.0-beta.0]: https://github.com/choruzo/CLI/compare/v0.7.0...v0.8.0-beta.0
|
|
275
289
|
[0.7.0]: https://github.com/choruzo/CLI/compare/v0.6.0...v0.7.0
|
|
276
290
|
[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,
|
|
@@ -20804,7 +20811,15 @@ function formatInput(state) {
|
|
|
20804
20811
|
return truncateLabel(`${from} \u2192 ${to}`);
|
|
20805
20812
|
}
|
|
20806
20813
|
}
|
|
20807
|
-
return truncateLabel(
|
|
20814
|
+
return truncateLabel(labelOf(src[keys[0]]));
|
|
20815
|
+
}
|
|
20816
|
+
function labelOf(value2) {
|
|
20817
|
+
if (value2 === null || value2 === void 0) return "";
|
|
20818
|
+
if (typeof value2 !== "object") return String(value2);
|
|
20819
|
+
if (!Array.isArray(value2)) return JSON.stringify(value2);
|
|
20820
|
+
const first = value2[0];
|
|
20821
|
+
const head = typeof first === "object" && first !== null ? Object.values(first).find((v) => typeof v === "string") ?? JSON.stringify(first) : String(first ?? "");
|
|
20822
|
+
return value2.length > 1 ? `${head} (+${value2.length - 1})` : head;
|
|
20808
20823
|
}
|
|
20809
20824
|
function formatDuration(ms) {
|
|
20810
20825
|
return `${(ms / 1e3).toFixed(1)}s`;
|
|
@@ -21663,6 +21678,19 @@ var init_CommandPalette = __esm({
|
|
|
21663
21678
|
});
|
|
21664
21679
|
|
|
21665
21680
|
// src/cli/ui/session-commands.ts
|
|
21681
|
+
function matchCommand(input, commands = SESSION_COMMANDS) {
|
|
21682
|
+
const line = input.trim();
|
|
21683
|
+
let best = null;
|
|
21684
|
+
for (const c of commands) {
|
|
21685
|
+
if (line !== c.name && !line.startsWith(c.name + " ")) continue;
|
|
21686
|
+
if (!best || c.name.length > best.name.length) best = c;
|
|
21687
|
+
}
|
|
21688
|
+
return best;
|
|
21689
|
+
}
|
|
21690
|
+
function isBusyCommand(input) {
|
|
21691
|
+
const match = matchCommand(input);
|
|
21692
|
+
return match !== null && BUSY_COMMAND_NAMES.has(match.name);
|
|
21693
|
+
}
|
|
21666
21694
|
function filterCommands(input, commands = SESSION_COMMANDS) {
|
|
21667
21695
|
const trimmed = input.trimStart();
|
|
21668
21696
|
if (!trimmed.startsWith("/")) return [];
|
|
@@ -21679,7 +21707,7 @@ function filterProfiles(input, profiles) {
|
|
|
21679
21707
|
function slashCommandName(input) {
|
|
21680
21708
|
return /^(\/[A-Za-z][\w-]*)(\s|$)/.exec(input.trimStart())?.[1] ?? null;
|
|
21681
21709
|
}
|
|
21682
|
-
var SESSION_COMMANDS;
|
|
21710
|
+
var SESSION_COMMANDS, BUSY_COMMAND_NAMES, BUSY_COMMANDS;
|
|
21683
21711
|
var init_session_commands = __esm({
|
|
21684
21712
|
"src/cli/ui/session-commands.ts"() {
|
|
21685
21713
|
"use strict";
|
|
@@ -21849,6 +21877,28 @@ var init_session_commands = __esm({
|
|
|
21849
21877
|
{ name: "/quit", description: "Termina la sesi\xF3n y guarda el historial", hasArgs: false },
|
|
21850
21878
|
{ name: "/exit", description: "Termina la sesi\xF3n y guarda el historial", hasArgs: false }
|
|
21851
21879
|
];
|
|
21880
|
+
BUSY_COMMAND_NAMES = /* @__PURE__ */ new Set([
|
|
21881
|
+
"/help",
|
|
21882
|
+
"/context",
|
|
21883
|
+
"/todo",
|
|
21884
|
+
"/changes",
|
|
21885
|
+
"/jobs",
|
|
21886
|
+
"/jobs cancel",
|
|
21887
|
+
"/auditor",
|
|
21888
|
+
"/auditor stop",
|
|
21889
|
+
"/debug",
|
|
21890
|
+
"/tools",
|
|
21891
|
+
"/agents",
|
|
21892
|
+
"/env",
|
|
21893
|
+
"/memory show",
|
|
21894
|
+
"/memory list",
|
|
21895
|
+
"/memory search",
|
|
21896
|
+
"/sessions list",
|
|
21897
|
+
"/config get"
|
|
21898
|
+
]);
|
|
21899
|
+
BUSY_COMMANDS = SESSION_COMMANDS.filter(
|
|
21900
|
+
(c) => BUSY_COMMAND_NAMES.has(c.name)
|
|
21901
|
+
);
|
|
21852
21902
|
}
|
|
21853
21903
|
});
|
|
21854
21904
|
|
|
@@ -24677,12 +24727,21 @@ function reducer(state, action) {
|
|
|
24677
24727
|
}
|
|
24678
24728
|
case "AGENT_EVENT": {
|
|
24679
24729
|
const ev = action.event;
|
|
24730
|
+
if (/^(tool_|subagent_|questions_|plan_)/.test(ev.type) && state.currentItem?.kind === "agent" && state.currentItem.text && !state.currentItem.textBreak) {
|
|
24731
|
+
return reducer(
|
|
24732
|
+
{ ...state, currentItem: { ...state.currentItem, textBreak: true } },
|
|
24733
|
+
action
|
|
24734
|
+
);
|
|
24735
|
+
}
|
|
24680
24736
|
if (ev.type === "text_delta") {
|
|
24681
24737
|
return {
|
|
24682
24738
|
...state,
|
|
24683
24739
|
currentItem: updateCurrentAgent(state.currentItem, (item) => ({
|
|
24684
24740
|
...item,
|
|
24685
|
-
text: item.
|
|
24741
|
+
text: item.textBreak ? `${item.text.trimEnd()}
|
|
24742
|
+
|
|
24743
|
+
${ev.delta}` : item.text + ev.delta,
|
|
24744
|
+
textBreak: false,
|
|
24686
24745
|
thinkingOpen: false
|
|
24687
24746
|
}))
|
|
24688
24747
|
};
|
|
@@ -25294,8 +25353,8 @@ function App({
|
|
|
25294
25353
|
const [subagentViewHint, setSubagentViewHint] = useState9(null);
|
|
25295
25354
|
const [paletteIndex, setPaletteIndex] = useState9(0);
|
|
25296
25355
|
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);
|
|
25356
|
+
const paletteEligible = !state.pendingConfirm && !state.pendingQuestions && !overlay && state.focusState === "input" && !paletteDismissed && /^[/@]/.test(state.inputValue.trimStart());
|
|
25357
|
+
const paletteItems = !paletteEligible ? [] : state.inputValue.trimStart().startsWith("@") ? state.thinking ? [] : filterProfiles(state.inputValue, profileRows) : filterCommands(state.inputValue, state.thinking ? BUSY_COMMANDS : SESSION_COMMANDS);
|
|
25299
25358
|
const effPaletteIndex = Math.min(paletteIndex, Math.max(paletteItems.length - 1, 0));
|
|
25300
25359
|
const handleInputChange = useCallback4((value2) => {
|
|
25301
25360
|
setPaletteDismissed(false);
|
|
@@ -25390,18 +25449,28 @@ function App({
|
|
|
25390
25449
|
return;
|
|
25391
25450
|
}
|
|
25392
25451
|
}
|
|
25452
|
+
const settleInput = (value2) => {
|
|
25453
|
+
setTimeout(() => dispatch({ type: "INPUT_CHANGE", value: value2 }), 0);
|
|
25454
|
+
};
|
|
25393
25455
|
if (key.ctrl && input === "l") {
|
|
25456
|
+
if (state.thinking) {
|
|
25457
|
+
settleInput(state.inputValue);
|
|
25458
|
+
return;
|
|
25459
|
+
}
|
|
25394
25460
|
executeCommandRef.current?.("/clear");
|
|
25461
|
+
settleInput("");
|
|
25395
25462
|
return;
|
|
25396
25463
|
}
|
|
25397
25464
|
if (key.ctrl && input === "t") {
|
|
25398
25465
|
dispatch({ type: "TOGGLE_TODO" });
|
|
25466
|
+
settleInput(state.inputValue);
|
|
25399
25467
|
return;
|
|
25400
25468
|
}
|
|
25401
25469
|
if (key.ctrl && input === "u") {
|
|
25402
25470
|
draftRef.current = "";
|
|
25403
25471
|
setHistoryIndex(null);
|
|
25404
25472
|
dispatch({ type: "INPUT_CHANGE", value: "" });
|
|
25473
|
+
settleInput("");
|
|
25405
25474
|
return;
|
|
25406
25475
|
}
|
|
25407
25476
|
if (state.focusState === "input" && (key.upArrow || key.downArrow)) {
|
|
@@ -26401,7 +26470,20 @@ Uso: /provider <alias> para cambiar en esta sesi\xF3n \xB7 /provider remove <ali
|
|
|
26401
26470
|
}
|
|
26402
26471
|
if (state.thinking) {
|
|
26403
26472
|
if (/^[/@]/.test(cmd)) {
|
|
26404
|
-
|
|
26473
|
+
const sel = paletteItems[effPaletteIndex];
|
|
26474
|
+
if (sel && sel.name !== cmd) {
|
|
26475
|
+
if (sel.hasArgs) completePaletteSelection(sel.name, true);
|
|
26476
|
+
else executeCommand(sel.name);
|
|
26477
|
+
return;
|
|
26478
|
+
}
|
|
26479
|
+
if (isBusyCommand(cmd)) {
|
|
26480
|
+
setInputHint(null);
|
|
26481
|
+
executeCommand(cmd);
|
|
26482
|
+
return;
|
|
26483
|
+
}
|
|
26484
|
+
setInputHint(
|
|
26485
|
+
"Not available while the agent is working (Ctrl+C cancels). Type / to see what is."
|
|
26486
|
+
);
|
|
26405
26487
|
return;
|
|
26406
26488
|
}
|
|
26407
26489
|
setInputHint(null);
|
|
@@ -26879,7 +26961,7 @@ async function settle(step, fn) {
|
|
|
26879
26961
|
}
|
|
26880
26962
|
}
|
|
26881
26963
|
function resolveVersion() {
|
|
26882
|
-
if (true) return "0.8.0-beta.
|
|
26964
|
+
if (true) return "0.8.0-beta.1";
|
|
26883
26965
|
try {
|
|
26884
26966
|
const thisDir = dirname14(fileURLToPath2(import.meta.url));
|
|
26885
26967
|
const pkg = JSON.parse(
|
|
@@ -32734,7 +32816,7 @@ function resolveResult(ref, dir) {
|
|
|
32734
32816
|
}
|
|
32735
32817
|
|
|
32736
32818
|
// src/cli/commands/eval.ts
|
|
32737
|
-
var VERSION = true ? "0.8.0-beta.
|
|
32819
|
+
var VERSION = true ? "0.8.0-beta.1" : "dev";
|
|
32738
32820
|
var fail2 = (message) => {
|
|
32739
32821
|
process.stderr.write(`${message}
|
|
32740
32822
|
`);
|
|
@@ -33347,7 +33429,7 @@ var statsCommand = new Command14("stats").description(
|
|
|
33347
33429
|
init_loader();
|
|
33348
33430
|
init_schema_version();
|
|
33349
33431
|
function resolveVersion2() {
|
|
33350
|
-
if (true) return "0.8.0-beta.
|
|
33432
|
+
if (true) return "0.8.0-beta.1";
|
|
33351
33433
|
const thisDir = dirname19(fileURLToPath5(import.meta.url));
|
|
33352
33434
|
const pkg = JSON.parse(readFileSync26(join32(thisDir, "..", "..", "package.json"), "utf-8"));
|
|
33353
33435
|
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.1",
|
|
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",
|