stratum-cli 0.8.0-beta.1 → 0.8.0-beta.3
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/.stratumrc.json.example +3 -1
- package/CHANGELOG.md +21 -0
- package/dist/index.js +115 -37
- package/package.json +1 -1
package/.stratumrc.json.example
CHANGED
|
@@ -144,7 +144,9 @@
|
|
|
144
144
|
"agents": {
|
|
145
145
|
"defaultProfile": "general",
|
|
146
146
|
"maxConcurrency": 1,
|
|
147
|
-
"subagentRetentionDays": 30
|
|
147
|
+
"subagentRetentionDays": 30,
|
|
148
|
+
"subagentTimeoutMs": 1800000,
|
|
149
|
+
"subagentMaxIterations": 50
|
|
148
150
|
},
|
|
149
151
|
"skills": {
|
|
150
152
|
"enabled": true,
|
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,25 @@ 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.3] — 2026-10-12
|
|
10
|
+
|
|
11
|
+
Cuarta pre-release (`npm install -g stratum-cli@beta`).
|
|
12
|
+
|
|
13
|
+
### Cambiado
|
|
14
|
+
- **Los subagentes tienen más margen**: el tiempo máximo por defecto pasa de 5 a 30 minutos y las iteraciones de 25 a 50. Ambos se ajustan en la config con `agents.subagentTimeoutMs` (`0` quita el límite de tiempo) y `agents.subagentMaxIterations`; lo que un perfil declare en su `budget` sigue ganando.
|
|
15
|
+
|
|
16
|
+
### Corregido
|
|
17
|
+
- Un subagente que agotaba su tiempo aparecía como «cancelado», como si alguien lo hubiera parado. Ahora termina como presupuesto agotado, y el agente principal recibe el límite que se alcanzó, el aviso de que el trabajo parcial puede estar en disco y dónde se cambia.
|
|
18
|
+
|
|
19
|
+
## [0.8.0-beta.2] — 2026-10-12
|
|
20
|
+
|
|
21
|
+
Tercera pre-release (`npm install -g stratum-cli@beta`), con más arreglos de lo visto al probar la beta.
|
|
22
|
+
|
|
23
|
+
### Corregido
|
|
24
|
+
- **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`.
|
|
25
|
+
- 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`.
|
|
26
|
+
- 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.
|
|
27
|
+
|
|
9
28
|
## [0.8.0-beta.1] — 2026-10-12
|
|
10
29
|
|
|
11
30
|
Segunda pre-release (`npm install -g stratum-cli@beta`), con lo visto al probar la beta.0.
|
|
@@ -284,6 +303,8 @@ Primera versión etiquetada. Hitos 0 y 1.
|
|
|
284
303
|
- `/init` para generar o actualizar `STRATUM.md`.
|
|
285
304
|
- Render de markdown de las respuestas.
|
|
286
305
|
|
|
306
|
+
[0.8.0-beta.3]: https://github.com/choruzo/CLI/compare/v0.8.0-beta.2...v0.8.0-beta.3
|
|
307
|
+
[0.8.0-beta.2]: https://github.com/choruzo/CLI/compare/v0.8.0-beta.1...v0.8.0-beta.2
|
|
287
308
|
[0.8.0-beta.1]: https://github.com/choruzo/CLI/compare/v0.8.0-beta.0...v0.8.0-beta.1
|
|
288
309
|
[0.8.0-beta.0]: https://github.com/choruzo/CLI/compare/v0.7.0...v0.8.0-beta.0
|
|
289
310
|
[0.7.0]: https://github.com/choruzo/CLI/compare/v0.6.0...v0.7.0
|
package/dist/index.js
CHANGED
|
@@ -643,7 +643,15 @@ var init_schema = __esm({
|
|
|
643
643
|
* Días que se conservan los registros de `.stratum/subagents/` (8B endurecido).
|
|
644
644
|
* `chat` purga al arrancar lo que lleve más sin tocarse; `0` lo desactiva.
|
|
645
645
|
*/
|
|
646
|
-
subagentRetentionDays: z.number().int().nonnegative().default(30)
|
|
646
|
+
subagentRetentionDays: z.number().int().nonnegative().default(30),
|
|
647
|
+
/**
|
|
648
|
+
* Tiempo máximo de un subagente en ms, para los perfiles que no declaran
|
|
649
|
+
* `budget.timeoutMs`. `0` quita el límite: solo lo paran sus iteraciones,
|
|
650
|
+
* la cancelación del usuario o el fin del turno.
|
|
651
|
+
*/
|
|
652
|
+
subagentTimeoutMs: z.number().int().nonnegative().default(30 * 60 * 1e3),
|
|
653
|
+
/** Iteraciones máximas de un subagente, para los perfiles sin `budget.maxIterations`. */
|
|
654
|
+
subagentMaxIterations: z.number().int().positive().default(50)
|
|
647
655
|
}).default({}),
|
|
648
656
|
/**
|
|
649
657
|
* Registro de skills (Hito 12). Las skills en sí son ficheros sueltos
|
|
@@ -15921,6 +15929,15 @@ import { existsSync as existsSync11, readdirSync as readdirSync6, readFileSync a
|
|
|
15921
15929
|
import { homedir as homedir4 } from "os";
|
|
15922
15930
|
import { join as join16, resolve as resolve12 } from "path";
|
|
15923
15931
|
import { z as z25 } from "zod";
|
|
15932
|
+
function resolveSubagentBudget(profile, agents) {
|
|
15933
|
+
const declared = profile.declaredBudget ?? {};
|
|
15934
|
+
const own = (key) => declared[key] ?? (profile.budget[key] !== DEFAULT_BUDGET[key] ? profile.budget[key] : void 0);
|
|
15935
|
+
return {
|
|
15936
|
+
maxIterations: own("maxIterations") ?? agents.subagentMaxIterations,
|
|
15937
|
+
maxTokens: declared.maxTokens ?? profile.budget.maxTokens,
|
|
15938
|
+
timeoutMs: own("timeoutMs") ?? agents.subagentTimeoutMs
|
|
15939
|
+
};
|
|
15940
|
+
}
|
|
15924
15941
|
function isValidProfileName(name) {
|
|
15925
15942
|
return PROFILE_NAME_RE.test(name) && !RESERVED_PROFILE_NAMES.has(name);
|
|
15926
15943
|
}
|
|
@@ -15964,6 +15981,7 @@ function parseProfileDetailed(name, raw) {
|
|
|
15964
15981
|
destructivePolicy: fm.destructivePolicy,
|
|
15965
15982
|
budget,
|
|
15966
15983
|
budgetDeclared: fm.budget !== void 0,
|
|
15984
|
+
declaredBudget: fm.budget ?? {},
|
|
15967
15985
|
systemPromptFragment: body.trim() || GENERAL_PROFILE.systemPromptFragment
|
|
15968
15986
|
}
|
|
15969
15987
|
};
|
|
@@ -15986,7 +16004,7 @@ var init_profiles = __esm({
|
|
|
15986
16004
|
init_frontmatter();
|
|
15987
16005
|
init_logging();
|
|
15988
16006
|
log15 = getLogger("agent");
|
|
15989
|
-
DEFAULT_BUDGET = { maxIterations:
|
|
16007
|
+
DEFAULT_BUDGET = { maxIterations: 50, timeoutMs: 30 * 60 * 1e3 };
|
|
15990
16008
|
PROFILE_NAME_RE = /^[a-z0-9][a-z0-9._-]*$/;
|
|
15991
16009
|
RESERVED_PROFILE_NAMES = /* @__PURE__ */ new Set(["off", "default"]);
|
|
15992
16010
|
DESCRIPTION_CAP = 160;
|
|
@@ -16309,10 +16327,10 @@ async function runSubagent(opts) {
|
|
|
16309
16327
|
let tokenStatus = "unavailable";
|
|
16310
16328
|
let currentText = "";
|
|
16311
16329
|
let lastError;
|
|
16330
|
+
const budget = resolveSubagentBudget(profile, config.agents);
|
|
16312
16331
|
let signal = parentSignal;
|
|
16313
|
-
|
|
16314
|
-
|
|
16315
|
-
}
|
|
16332
|
+
const timeLimit = budget.timeoutMs && budget.timeoutMs > 0 ? AbortSignal.timeout(budget.timeoutMs) : null;
|
|
16333
|
+
if (timeLimit) signal = AbortSignal.any([parentSignal, timeLimit]);
|
|
16316
16334
|
let router;
|
|
16317
16335
|
try {
|
|
16318
16336
|
if (opts.makeRouter) {
|
|
@@ -16384,8 +16402,8 @@ async function runSubagent(opts) {
|
|
|
16384
16402
|
jobs: opts.jobs,
|
|
16385
16403
|
jobScope: task.id,
|
|
16386
16404
|
inbox: opts.inbox,
|
|
16387
|
-
maxIterations:
|
|
16388
|
-
maxTokens:
|
|
16405
|
+
maxIterations: budget.maxIterations,
|
|
16406
|
+
maxTokens: budget.maxTokens,
|
|
16389
16407
|
trace: opts.trace
|
|
16390
16408
|
};
|
|
16391
16409
|
log17.info("subagent run", {
|
|
@@ -16393,7 +16411,8 @@ async function runSubagent(opts) {
|
|
|
16393
16411
|
profile: profile.name,
|
|
16394
16412
|
provider: router.providerName,
|
|
16395
16413
|
model: router.model,
|
|
16396
|
-
maxIterations:
|
|
16414
|
+
maxIterations: budget.maxIterations,
|
|
16415
|
+
timeoutMs: budget.timeoutMs
|
|
16397
16416
|
});
|
|
16398
16417
|
let stopReason = "stop";
|
|
16399
16418
|
try {
|
|
@@ -16463,7 +16482,8 @@ async function runSubagent(opts) {
|
|
|
16463
16482
|
if (accounting.status !== "reported") {
|
|
16464
16483
|
log17.debug("subagent tokens sin dato", { id: task.id, tokenStatus: accounting.status });
|
|
16465
16484
|
}
|
|
16466
|
-
const
|
|
16485
|
+
const timedOut = timeLimit?.aborted === true && !parentSignal.aborted;
|
|
16486
|
+
const status = timedOut ? "budget_exceeded" : stopReason === "cancelled" ? "cancelled" : stopReason === "max_iterations" || stopReason === "budget_tokens" ? "budget_exceeded" : stopReason === "error" ? "failed" : "completed";
|
|
16467
16487
|
const summary = truncateToolOutput(
|
|
16468
16488
|
currentText.trim() || "El subagente termin\xF3 sin un resumen textual.",
|
|
16469
16489
|
RESULT_SUMMARY_CAP
|
|
@@ -16476,7 +16496,7 @@ async function runSubagent(opts) {
|
|
|
16476
16496
|
filesChanged: toFilesArray(filesChanged),
|
|
16477
16497
|
decisions: decisions.length ? decisions : void 0,
|
|
16478
16498
|
usage: { iterations, tokens, tokenStatus, durationMs: Date.now() - start },
|
|
16479
|
-
error: status === "failed" && lastError ? `Subagent failed: ${lastError}` : statusErrorText(status)
|
|
16499
|
+
error: status === "failed" && lastError ? `Subagent failed: ${lastError}` : timedOut ? `Subagent ran out of time (${Math.round((budget.timeoutMs ?? 0) / 1e3)} s limit) before finishing. Its partial work may be on disk: check before redoing it. The limit is agents.subagentTimeoutMs in .stratumrc.json (0 = no limit), or budget.timeoutMs in the profile.` : statusErrorText(status)
|
|
16480
16500
|
};
|
|
16481
16501
|
}
|
|
16482
16502
|
function canonicalChangePath(target, baseCwd, rawPath, cwd) {
|
|
@@ -16720,7 +16740,7 @@ async function* executeDelegations(jobs, ctx) {
|
|
|
16720
16740
|
task: job.taskText,
|
|
16721
16741
|
profile: job.profile.name,
|
|
16722
16742
|
context: job.context,
|
|
16723
|
-
budget: job.profile.
|
|
16743
|
+
budget: resolveSubagentBudget(job.profile, ctx.config.agents)
|
|
16724
16744
|
},
|
|
16725
16745
|
profile: job.profile,
|
|
16726
16746
|
registry: ctx.registry,
|
|
@@ -19726,6 +19746,16 @@ var init_store2 = __esm({
|
|
|
19726
19746
|
mkdirSync7(this.sessionsDir, { recursive: true });
|
|
19727
19747
|
}
|
|
19728
19748
|
}
|
|
19749
|
+
/**
|
|
19750
|
+
* Un id que no está en disco. El id lleva la hora al segundo y tres
|
|
19751
|
+
* caracteres al azar: dos sesiones guardadas en el mismo segundo pueden
|
|
19752
|
+
* coincidir, y la segunda pisaría a la primera.
|
|
19753
|
+
*/
|
|
19754
|
+
freshSessionId() {
|
|
19755
|
+
let id = generateSessionId();
|
|
19756
|
+
while (existsSync16(this.sessionPath(id))) id = generateSessionId();
|
|
19757
|
+
return id;
|
|
19758
|
+
}
|
|
19729
19759
|
sessionPath(id) {
|
|
19730
19760
|
if (!isSessionId(id)) {
|
|
19731
19761
|
throw new Error(`Id de sesi\xF3n inv\xE1lido: ${JSON.stringify(id.slice(0, 80))}`);
|
|
@@ -19747,14 +19777,14 @@ var init_store2 = __esm({
|
|
|
19747
19777
|
async save(params) {
|
|
19748
19778
|
this.ensureDir();
|
|
19749
19779
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
19750
|
-
let id = params.existingId ??
|
|
19780
|
+
let id = params.existingId ?? this.freshSessionId();
|
|
19751
19781
|
let createdAt = params.createdAt ?? now;
|
|
19752
19782
|
let forkedFrom = params.forkedFrom;
|
|
19753
19783
|
if (params.existingId) {
|
|
19754
19784
|
const onDisk = this.diskUpdatedAt(params.existingId);
|
|
19755
19785
|
if (onDisk !== null && onDisk !== params.expectedUpdatedAt) {
|
|
19756
19786
|
forkedFrom = params.existingId;
|
|
19757
|
-
id =
|
|
19787
|
+
id = this.freshSessionId();
|
|
19758
19788
|
createdAt = now;
|
|
19759
19789
|
log21.warn("session changed on disk: saving as a fork", { from: forkedFrom, to: id });
|
|
19760
19790
|
}
|
|
@@ -20781,6 +20811,51 @@ var init_spinner = __esm({
|
|
|
20781
20811
|
}
|
|
20782
20812
|
});
|
|
20783
20813
|
|
|
20814
|
+
// src/cli/ui/tool-arg-label.ts
|
|
20815
|
+
function labelOf(value2) {
|
|
20816
|
+
if (value2 === null || value2 === void 0) return "";
|
|
20817
|
+
if (typeof value2 !== "object") return String(value2);
|
|
20818
|
+
if (!Array.isArray(value2)) return JSON.stringify(value2);
|
|
20819
|
+
const first = value2[0];
|
|
20820
|
+
const head = typeof first === "object" && first !== null ? Object.values(first).find((v) => typeof v === "string") ?? JSON.stringify(first) : String(first ?? "");
|
|
20821
|
+
return value2.length > 1 ? `${head} (+${value2.length - 1})` : head;
|
|
20822
|
+
}
|
|
20823
|
+
function primaryArg(input) {
|
|
20824
|
+
if (!input) return "";
|
|
20825
|
+
const keys = Object.keys(input);
|
|
20826
|
+
if (keys.length === 0) return "";
|
|
20827
|
+
const key = IDENTIFYING_KEYS.find((k) => typeof input[k] === "string" && input[k] !== "") ?? keys[0];
|
|
20828
|
+
return labelOf(input[key]);
|
|
20829
|
+
}
|
|
20830
|
+
function tailWindow(items, max) {
|
|
20831
|
+
const keep = Math.max(1, Math.floor(max));
|
|
20832
|
+
if (items.length <= keep) return { hidden: 0, visible: [...items] };
|
|
20833
|
+
return { hidden: items.length - keep, visible: items.slice(-keep) };
|
|
20834
|
+
}
|
|
20835
|
+
function treeToolBudget(rows, nodes, reservedRows = 22) {
|
|
20836
|
+
const perNode = Math.floor((rows - reservedRows) / Math.max(1, nodes)) - 2;
|
|
20837
|
+
return Math.min(6, Math.max(1, perNode));
|
|
20838
|
+
}
|
|
20839
|
+
var IDENTIFYING_KEYS;
|
|
20840
|
+
var init_tool_arg_label = __esm({
|
|
20841
|
+
"src/cli/ui/tool-arg-label.ts"() {
|
|
20842
|
+
"use strict";
|
|
20843
|
+
init_esm_shims();
|
|
20844
|
+
IDENTIFYING_KEYS = [
|
|
20845
|
+
"command",
|
|
20846
|
+
"path",
|
|
20847
|
+
"file_path",
|
|
20848
|
+
"filePath",
|
|
20849
|
+
"pattern",
|
|
20850
|
+
"query",
|
|
20851
|
+
"url",
|
|
20852
|
+
"task",
|
|
20853
|
+
"jobId",
|
|
20854
|
+
"name"
|
|
20855
|
+
];
|
|
20856
|
+
}
|
|
20857
|
+
});
|
|
20858
|
+
|
|
20784
20859
|
// src/cli/ui/ToolCallBlock.tsx
|
|
20785
20860
|
import { Box, Text } from "ink";
|
|
20786
20861
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -20811,15 +20886,7 @@ function formatInput(state) {
|
|
|
20811
20886
|
return truncateLabel(`${from} \u2192 ${to}`);
|
|
20812
20887
|
}
|
|
20813
20888
|
}
|
|
20814
|
-
return truncateLabel(
|
|
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;
|
|
20889
|
+
return truncateLabel(primaryArg(src));
|
|
20823
20890
|
}
|
|
20824
20891
|
function formatDuration(ms) {
|
|
20825
20892
|
return `${(ms / 1e3).toFixed(1)}s`;
|
|
@@ -20940,6 +21007,7 @@ var init_ToolCallBlock = __esm({
|
|
|
20940
21007
|
init_esm_shims();
|
|
20941
21008
|
init_theme();
|
|
20942
21009
|
init_spinner();
|
|
21010
|
+
init_tool_arg_label();
|
|
20943
21011
|
MAX_EXPANDED_LINES = 10;
|
|
20944
21012
|
SLOW_MS = 1e3;
|
|
20945
21013
|
}
|
|
@@ -22398,7 +22466,7 @@ var init_SubagentBlock = __esm({
|
|
|
22398
22466
|
});
|
|
22399
22467
|
|
|
22400
22468
|
// src/cli/ui/AgentTree.tsx
|
|
22401
|
-
import { Box as Box12, Text as Text13 } from "ink";
|
|
22469
|
+
import { Box as Box12, Text as Text13, useStdout as useStdout3 } from "ink";
|
|
22402
22470
|
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
22403
22471
|
function fmtDur2(ms) {
|
|
22404
22472
|
return `${(ms / 1e3).toFixed(1)}s`;
|
|
@@ -22408,10 +22476,7 @@ function truncate2(text, max) {
|
|
|
22408
22476
|
return oneLine.length > max ? oneLine.slice(0, max - 1) + "\u2026" : oneLine;
|
|
22409
22477
|
}
|
|
22410
22478
|
function firstArg(tc) {
|
|
22411
|
-
|
|
22412
|
-
const keys = Object.keys(src);
|
|
22413
|
-
if (keys.length === 0) return "";
|
|
22414
|
-
return truncate2(String(src[keys[0]] ?? ""), 40);
|
|
22479
|
+
return truncate2(primaryArg(tc.input), 40);
|
|
22415
22480
|
}
|
|
22416
22481
|
function ToolLine({ tc }) {
|
|
22417
22482
|
const icon = tc.status === "completed" ? "\u2713" : tc.status === "error" ? "\u2717" : "\u27F3";
|
|
@@ -22446,7 +22511,7 @@ function nodeIcon(status) {
|
|
|
22446
22511
|
return { icon: "\u22B3", color: theme.accent };
|
|
22447
22512
|
}
|
|
22448
22513
|
}
|
|
22449
|
-
function SubagentNode({ node, speaking, focused, expanded, isLast, now }) {
|
|
22514
|
+
function SubagentNode({ node, speaking, focused, expanded, isLast, now, maxToolLines }) {
|
|
22450
22515
|
const running = node.status === "running";
|
|
22451
22516
|
const elapsedMs = node.startedAt ? Math.max(0, now - node.startedAt) : 0;
|
|
22452
22517
|
const { icon, color } = nodeIcon(node.status);
|
|
@@ -22458,7 +22523,7 @@ function SubagentNode({ node, speaking, focused, expanded, isLast, now }) {
|
|
|
22458
22523
|
node.iterations !== void 0 ? `${node.iterations} it` : ""
|
|
22459
22524
|
].filter(Boolean).join(" \xB7 ");
|
|
22460
22525
|
const tail2 = node.status === "failed" && node.error ? truncate2(node.error, 44) : node.status === "completed" && node.summary ? truncate2(node.summary, 44) : truncate2(node.task, 44);
|
|
22461
|
-
const tcs = node.toolCalls ?? [];
|
|
22526
|
+
const { hidden, visible: tcs } = tailWindow(node.toolCalls ?? [], maxToolLines);
|
|
22462
22527
|
const files = node.filesChanged ?? [];
|
|
22463
22528
|
return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", children: [
|
|
22464
22529
|
/* @__PURE__ */ jsxs11(Text13, { wrap: "truncate-end", children: [
|
|
@@ -22482,6 +22547,15 @@ function SubagentNode({ node, speaking, focused, expanded, isLast, now }) {
|
|
|
22482
22547
|
] }),
|
|
22483
22548
|
focused ? /* @__PURE__ */ jsx13(Text13, { color: theme.accent, children: " \u25C0" }) : null
|
|
22484
22549
|
] }),
|
|
22550
|
+
hidden > 0 && /* @__PURE__ */ jsxs11(Text13, { color: theme.textDisabled, wrap: "truncate-end", children: [
|
|
22551
|
+
" ",
|
|
22552
|
+
"\u2026 ",
|
|
22553
|
+
hidden,
|
|
22554
|
+
" ",
|
|
22555
|
+
hidden === 1 ? "acci\xF3n anterior" : "acciones anteriores",
|
|
22556
|
+
" ",
|
|
22557
|
+
"(/subagents para verlas)"
|
|
22558
|
+
] }),
|
|
22485
22559
|
tcs.map((tc) => /* @__PURE__ */ jsx13(ToolLine, { tc }, tc.id)),
|
|
22486
22560
|
expanded && node.summary && /* @__PURE__ */ jsxs11(Text13, { color: theme.textFaint, wrap: "truncate-end", children: [
|
|
22487
22561
|
" ",
|
|
@@ -22507,6 +22581,8 @@ function AgentTree({
|
|
|
22507
22581
|
expandedBlockIds,
|
|
22508
22582
|
now = Date.now()
|
|
22509
22583
|
}) {
|
|
22584
|
+
const { stdout } = useStdout3();
|
|
22585
|
+
const maxToolLines = treeToolBudget(stdout?.rows ?? 24, nodes.length);
|
|
22510
22586
|
const allTerminal = nodes.every((n) => TERMINAL.has(n.status));
|
|
22511
22587
|
if (allTerminal) {
|
|
22512
22588
|
const completed = nodes.filter((n) => n.status === "completed").length;
|
|
@@ -22552,7 +22628,8 @@ function AgentTree({
|
|
|
22552
22628
|
focused: focusedBlockId === n.id,
|
|
22553
22629
|
expanded: expandedBlockIds?.has(n.id) ?? false,
|
|
22554
22630
|
isLast: i === nodes.length - 1,
|
|
22555
|
-
now
|
|
22631
|
+
now,
|
|
22632
|
+
maxToolLines
|
|
22556
22633
|
},
|
|
22557
22634
|
n.id
|
|
22558
22635
|
))
|
|
@@ -22565,6 +22642,7 @@ var init_AgentTree = __esm({
|
|
|
22565
22642
|
init_esm_shims();
|
|
22566
22643
|
init_theme();
|
|
22567
22644
|
init_spinner();
|
|
22645
|
+
init_tool_arg_label();
|
|
22568
22646
|
TERMINAL = /* @__PURE__ */ new Set([
|
|
22569
22647
|
"completed",
|
|
22570
22648
|
"failed",
|
|
@@ -22786,7 +22864,7 @@ var init_AgentMessage = __esm({
|
|
|
22786
22864
|
});
|
|
22787
22865
|
|
|
22788
22866
|
// src/cli/ui/MessageList.tsx
|
|
22789
|
-
import { Box as Box15, Static as Static2, useStdout as
|
|
22867
|
+
import { Box as Box15, Static as Static2, useStdout as useStdout4 } from "ink";
|
|
22790
22868
|
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
22791
22869
|
function renderItem(item, key, focusedBlockId, expandedBlockIds, debug, now, liveTextLines, liveColumns, liveActionLimit) {
|
|
22792
22870
|
if (item.kind === "user") {
|
|
@@ -22836,7 +22914,7 @@ function MessageList({
|
|
|
22836
22914
|
now = Date.now(),
|
|
22837
22915
|
availableRows
|
|
22838
22916
|
}) {
|
|
22839
|
-
const { stdout } =
|
|
22917
|
+
const { stdout } = useStdout4();
|
|
22840
22918
|
const { contentWidth } = resolveLayout(stdout.columns ?? 80, stdout.rows ?? 24);
|
|
22841
22919
|
const terminalRows = availableRows ?? stdout.rows ?? 24;
|
|
22842
22920
|
const liveActionLimit = Math.max(1, Math.min(6, Math.floor((terminalRows - 8) / 2)));
|
|
@@ -23563,7 +23641,7 @@ var init_FatalError = __esm({
|
|
|
23563
23641
|
});
|
|
23564
23642
|
|
|
23565
23643
|
// src/cli/ui/ConversationView.tsx
|
|
23566
|
-
import { Box as Box26, Text as Text27, useStdout as
|
|
23644
|
+
import { Box as Box26, Text as Text27, useStdout as useStdout5 } from "ink";
|
|
23567
23645
|
import { jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
23568
23646
|
function ConversationView({
|
|
23569
23647
|
completedItems,
|
|
@@ -23613,7 +23691,7 @@ function ConversationView({
|
|
|
23613
23691
|
const liveNow = useLiveClock(thinking);
|
|
23614
23692
|
const gateOpen = !!pendingConfirm || !!pendingQuestions?.length || !!pendingApproval;
|
|
23615
23693
|
const steerable = thinking && !gateOpen && !fatalError;
|
|
23616
|
-
const { stdout } =
|
|
23694
|
+
const { stdout } = useStdout5();
|
|
23617
23695
|
const terminalRows = stdout.rows ?? 24;
|
|
23618
23696
|
const panelMaxSteps = Math.max(2, Math.min(5, Math.floor(terminalRows / 5)));
|
|
23619
23697
|
const jobsClock = jobsNow ?? Date.now();
|
|
@@ -26961,7 +27039,7 @@ async function settle(step, fn) {
|
|
|
26961
27039
|
}
|
|
26962
27040
|
}
|
|
26963
27041
|
function resolveVersion() {
|
|
26964
|
-
if (true) return "0.8.0-beta.
|
|
27042
|
+
if (true) return "0.8.0-beta.3";
|
|
26965
27043
|
try {
|
|
26966
27044
|
const thisDir = dirname14(fileURLToPath2(import.meta.url));
|
|
26967
27045
|
const pkg = JSON.parse(
|
|
@@ -32816,7 +32894,7 @@ function resolveResult(ref, dir) {
|
|
|
32816
32894
|
}
|
|
32817
32895
|
|
|
32818
32896
|
// src/cli/commands/eval.ts
|
|
32819
|
-
var VERSION = true ? "0.8.0-beta.
|
|
32897
|
+
var VERSION = true ? "0.8.0-beta.3" : "dev";
|
|
32820
32898
|
var fail2 = (message) => {
|
|
32821
32899
|
process.stderr.write(`${message}
|
|
32822
32900
|
`);
|
|
@@ -33429,7 +33507,7 @@ var statsCommand = new Command14("stats").description(
|
|
|
33429
33507
|
init_loader();
|
|
33430
33508
|
init_schema_version();
|
|
33431
33509
|
function resolveVersion2() {
|
|
33432
|
-
if (true) return "0.8.0-beta.
|
|
33510
|
+
if (true) return "0.8.0-beta.3";
|
|
33433
33511
|
const thisDir = dirname19(fileURLToPath5(import.meta.url));
|
|
33434
33512
|
const pkg = JSON.parse(readFileSync26(join32(thisDir, "..", "..", "package.json"), "utf-8"));
|
|
33435
33513
|
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.3",
|
|
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",
|