agentlas 1.0.25 → 1.0.26
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 +12 -0
- package/engine/commands/list.cjs +54 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.26 — 2026-08-03
|
|
4
|
+
|
|
5
|
+
- **`agentlas list` stops letting the terminal cut its own output.** Slugs were
|
|
6
|
+
padded to a fixed width, so a longer one pushed that row's description out of
|
|
7
|
+
alignment, and the tagline had no bound at all — the terminal cut it mid-word
|
|
8
|
+
with no marker, so a short description and a truncated one looked identical.
|
|
9
|
+
Rows reached 109 display columns in an 80-column terminal. The slug column now
|
|
10
|
+
sizes to the widest slug present and the tagline is truncated on a word
|
|
11
|
+
boundary with an explicit ellipsis, measured in display cells so Korean and
|
|
12
|
+
other wide characters are counted at their real width. COLUMNS is honoured when
|
|
13
|
+
stdout is not a TTY.
|
|
14
|
+
|
|
3
15
|
## 1.0.25 — 2026-08-02
|
|
4
16
|
|
|
5
17
|
- **Every Terminal session now closes a governed learning episode.** Direct
|
package/engine/commands/list.cjs
CHANGED
|
@@ -39,10 +39,63 @@ function run(ctx) {
|
|
|
39
39
|
if (!agents.length) {
|
|
40
40
|
ctx.out(" " + (en ? "(none yet — try: agentlas search \"what you need\")" : " (아직 없음 — agentlas search \"필요한 것\" 으로 찾아보세요)"));
|
|
41
41
|
}
|
|
42
|
+
// padEnd alone does not align: a slug longer than the pad pushes that row's
|
|
43
|
+
// description out, and an unbounded tagline wraps and gets cut mid-word by the
|
|
44
|
+
// terminal with no marker, so the user cannot tell a short description from a
|
|
45
|
+
// truncated one. Clamp the slug column to the widest slug present (bounded),
|
|
46
|
+
// and truncate the tagline on a word boundary with an explicit ellipsis.
|
|
47
|
+
const SLUG_MAX = 32;
|
|
48
|
+
const slugWidth = Math.min(
|
|
49
|
+
SLUG_MAX,
|
|
50
|
+
agents.reduce((w, a) => Math.max(w, String(a.slug || "").length), 0) || 24,
|
|
51
|
+
);
|
|
52
|
+
const clampSlug = (slug) => {
|
|
53
|
+
const s = String(slug || "");
|
|
54
|
+
return s.length > slugWidth ? `${s.slice(0, slugWidth - 1)}…` : s.padEnd(slugWidth);
|
|
55
|
+
};
|
|
56
|
+
// CJK renders two columns wide while String.length counts one, so a Korean
|
|
57
|
+
// tagline measured by length overflows the terminal and gets cut by the
|
|
58
|
+
// terminal itself — exactly the unmarked mid-word break this fix removes.
|
|
59
|
+
const cellWidth = (ch) => {
|
|
60
|
+
const cp = ch.codePointAt(0);
|
|
61
|
+
return (cp >= 0x1100 && (
|
|
62
|
+
cp <= 0x115f
|
|
63
|
+
|| (cp >= 0x2e80 && cp <= 0xa4cf && cp !== 0x303f)
|
|
64
|
+
|| (cp >= 0xac00 && cp <= 0xd7a3)
|
|
65
|
+
|| (cp >= 0xf900 && cp <= 0xfaff)
|
|
66
|
+
|| (cp >= 0xfe30 && cp <= 0xfe6f)
|
|
67
|
+
|| (cp >= 0xff00 && cp <= 0xff60)
|
|
68
|
+
|| (cp >= 0xffe0 && cp <= 0xffe6)
|
|
69
|
+
|| (cp >= 0x1f300 && cp <= 0x1f64f)
|
|
70
|
+
|| (cp >= 0x20000 && cp <= 0x3fffd)
|
|
71
|
+
)) ? 2 : 1;
|
|
72
|
+
};
|
|
73
|
+
const displayWidth = (text) => [...String(text || "")].reduce((w, ch) => w + cellWidth(ch), 0);
|
|
74
|
+
const clampTag = (text, budget) => {
|
|
75
|
+
const t = String(text || "").replace(/\s+/g, " ").trim();
|
|
76
|
+
if (displayWidth(t) <= budget) return t;
|
|
77
|
+
let out = "";
|
|
78
|
+
let w = 0;
|
|
79
|
+
for (const ch of t) {
|
|
80
|
+
const next = w + cellWidth(ch);
|
|
81
|
+
if (next > budget - 1) break;
|
|
82
|
+
out += ch;
|
|
83
|
+
w = next;
|
|
84
|
+
}
|
|
85
|
+
const lastSpace = out.lastIndexOf(" ");
|
|
86
|
+
return `${(lastSpace > out.length * 0.6 ? out.slice(0, lastSpace) : out).trimEnd()}…`;
|
|
87
|
+
};
|
|
88
|
+
// Not a TTY (piped, redirected, CI) leaves process.stdout.columns undefined.
|
|
89
|
+
// Honour COLUMNS the way ordinary Unix tools do before falling back, so the
|
|
90
|
+
// output is reproducible and testable outside a terminal.
|
|
91
|
+
const cols = Number(process.stdout.columns) || Number(process.env.COLUMNS) || 100;
|
|
42
92
|
for (const a of agents) {
|
|
43
93
|
const name = en && a.name_en ? a.name_en : a.name;
|
|
44
94
|
const tag = en && a.tagline_en ? a.tagline_en : a.tagline;
|
|
45
|
-
|
|
95
|
+
// 2 indent + slug + space + name + " — " + tagline must fit one line.
|
|
96
|
+
const budget = Math.max(20, cols - (2 + slugWidth + 1 + displayWidth(name) + 3));
|
|
97
|
+
const shown = tag ? clampTag(tag, budget) : "";
|
|
98
|
+
ctx.out(` ${ctx.ui.accent(clampSlug(a.slug))} ${name}${shown ? ctx.ui.dim(" — " + shown) : ""}`);
|
|
46
99
|
}
|
|
47
100
|
if (firms.length) {
|
|
48
101
|
ctx.out("");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentlas",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.26",
|
|
4
4
|
"description": "Agentlas project terminal — run project controllers and task-scoped agent teams from the terminal. Standalone: no desktop app process required.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"agentlas": "bin/agentlas.cjs"
|